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.
Files changed (342) hide show
  1. exonware/__init__.py +2 -1
  2. exonware/conf.py +2 -2
  3. exonware/xwsystem/__init__.py +115 -43
  4. exonware/xwsystem/base.py +30 -0
  5. exonware/xwsystem/caching/__init__.py +39 -13
  6. exonware/xwsystem/caching/base.py +24 -6
  7. exonware/xwsystem/caching/bloom_cache.py +2 -2
  8. exonware/xwsystem/caching/cache_manager.py +2 -1
  9. exonware/xwsystem/caching/conditional.py +2 -2
  10. exonware/xwsystem/caching/contracts.py +85 -139
  11. exonware/xwsystem/caching/decorators.py +6 -19
  12. exonware/xwsystem/caching/defs.py +2 -1
  13. exonware/xwsystem/caching/disk_cache.py +2 -1
  14. exonware/xwsystem/caching/distributed.py +2 -1
  15. exonware/xwsystem/caching/errors.py +2 -1
  16. exonware/xwsystem/caching/events.py +110 -27
  17. exonware/xwsystem/caching/eviction_strategies.py +2 -2
  18. exonware/xwsystem/caching/external_caching_python.py +701 -0
  19. exonware/xwsystem/caching/facade.py +253 -0
  20. exonware/xwsystem/caching/factory.py +300 -0
  21. exonware/xwsystem/caching/fluent.py +14 -12
  22. exonware/xwsystem/caching/integrity.py +21 -6
  23. exonware/xwsystem/caching/lfu_cache.py +2 -1
  24. exonware/xwsystem/caching/lfu_optimized.py +18 -6
  25. exonware/xwsystem/caching/lru_cache.py +7 -4
  26. exonware/xwsystem/caching/memory_bounded.py +2 -2
  27. exonware/xwsystem/caching/metrics_exporter.py +2 -2
  28. exonware/xwsystem/caching/observable_cache.py +2 -2
  29. exonware/xwsystem/caching/pluggable_cache.py +2 -2
  30. exonware/xwsystem/caching/rate_limiter.py +2 -2
  31. exonware/xwsystem/caching/read_through.py +2 -2
  32. exonware/xwsystem/caching/secure_cache.py +81 -28
  33. exonware/xwsystem/caching/serializable.py +9 -7
  34. exonware/xwsystem/caching/stats.py +2 -2
  35. exonware/xwsystem/caching/tagging.py +2 -2
  36. exonware/xwsystem/caching/ttl_cache.py +4 -3
  37. exonware/xwsystem/caching/two_tier_cache.py +6 -3
  38. exonware/xwsystem/caching/utils.py +30 -12
  39. exonware/xwsystem/caching/validation.py +2 -2
  40. exonware/xwsystem/caching/warming.py +6 -3
  41. exonware/xwsystem/caching/write_behind.py +15 -6
  42. exonware/xwsystem/config/__init__.py +11 -17
  43. exonware/xwsystem/config/base.py +5 -5
  44. exonware/xwsystem/config/contracts.py +93 -153
  45. exonware/xwsystem/config/defaults.py +3 -2
  46. exonware/xwsystem/config/defs.py +3 -2
  47. exonware/xwsystem/config/errors.py +2 -5
  48. exonware/xwsystem/config/logging.py +12 -8
  49. exonware/xwsystem/config/logging_setup.py +3 -2
  50. exonware/xwsystem/config/performance.py +73 -391
  51. exonware/xwsystem/config/performance_modes.py +9 -8
  52. exonware/xwsystem/config/version_manager.py +1 -0
  53. exonware/xwsystem/config.py +27 -0
  54. exonware/xwsystem/console/__init__.py +53 -0
  55. exonware/xwsystem/console/base.py +133 -0
  56. exonware/xwsystem/console/cli/__init__.py +61 -0
  57. exonware/xwsystem/{cli → console/cli}/args.py +27 -24
  58. exonware/xwsystem/{cli → console/cli}/base.py +18 -87
  59. exonware/xwsystem/{cli → console/cli}/colors.py +15 -13
  60. exonware/xwsystem/console/cli/console.py +98 -0
  61. exonware/xwsystem/{cli → console/cli}/contracts.py +51 -69
  62. exonware/xwsystem/console/cli/defs.py +87 -0
  63. exonware/xwsystem/console/cli/encoding.py +69 -0
  64. exonware/xwsystem/{cli → console/cli}/errors.py +8 -3
  65. exonware/xwsystem/console/cli/event_logger.py +166 -0
  66. exonware/xwsystem/{cli → console/cli}/progress.py +25 -21
  67. exonware/xwsystem/{cli → console/cli}/prompts.py +3 -2
  68. exonware/xwsystem/{cli → console/cli}/tables.py +27 -24
  69. exonware/xwsystem/console/contracts.py +113 -0
  70. exonware/xwsystem/console/defs.py +154 -0
  71. exonware/xwsystem/console/errors.py +34 -0
  72. exonware/xwsystem/console/event_logger.py +385 -0
  73. exonware/xwsystem/console/writer.py +132 -0
  74. exonware/xwsystem/contracts.py +28 -0
  75. exonware/xwsystem/data_structures/__init__.py +23 -0
  76. exonware/xwsystem/data_structures/trie.py +34 -0
  77. exonware/xwsystem/data_structures/union_find.py +144 -0
  78. exonware/xwsystem/defs.py +17 -0
  79. exonware/xwsystem/errors.py +23 -0
  80. exonware/xwsystem/facade.py +62 -0
  81. exonware/xwsystem/http_client/__init__.py +22 -1
  82. exonware/xwsystem/http_client/advanced_client.py +8 -5
  83. exonware/xwsystem/http_client/base.py +3 -2
  84. exonware/xwsystem/http_client/client.py +7 -4
  85. exonware/xwsystem/http_client/contracts.py +42 -56
  86. exonware/xwsystem/http_client/defs.py +2 -1
  87. exonware/xwsystem/http_client/errors.py +2 -1
  88. exonware/xwsystem/http_client/facade.py +156 -0
  89. exonware/xwsystem/io/__init__.py +22 -3
  90. exonware/xwsystem/io/archive/__init__.py +8 -2
  91. exonware/xwsystem/io/archive/archive.py +1 -1
  92. exonware/xwsystem/io/archive/archive_files.py +4 -7
  93. exonware/xwsystem/io/archive/archivers.py +120 -10
  94. exonware/xwsystem/io/archive/base.py +4 -5
  95. exonware/xwsystem/io/archive/codec_integration.py +1 -2
  96. exonware/xwsystem/io/archive/compression.py +1 -2
  97. exonware/xwsystem/io/archive/facade.py +263 -0
  98. exonware/xwsystem/io/archive/formats/__init__.py +2 -3
  99. exonware/xwsystem/io/archive/formats/brotli_format.py +20 -7
  100. exonware/xwsystem/io/archive/formats/lz4_format.py +20 -7
  101. exonware/xwsystem/io/archive/formats/rar.py +11 -5
  102. exonware/xwsystem/io/archive/formats/sevenzip.py +12 -6
  103. exonware/xwsystem/io/archive/formats/squashfs_format.py +1 -2
  104. exonware/xwsystem/io/archive/formats/tar.py +52 -7
  105. exonware/xwsystem/io/archive/formats/wim_format.py +11 -5
  106. exonware/xwsystem/io/archive/formats/zip.py +1 -2
  107. exonware/xwsystem/io/archive/formats/zpaq_format.py +1 -2
  108. exonware/xwsystem/io/archive/formats/zstandard.py +20 -7
  109. exonware/xwsystem/io/base.py +119 -115
  110. exonware/xwsystem/io/codec/__init__.py +4 -2
  111. exonware/xwsystem/io/codec/base.py +19 -13
  112. exonware/xwsystem/io/codec/contracts.py +59 -2
  113. exonware/xwsystem/io/codec/registry.py +67 -21
  114. exonware/xwsystem/io/common/__init__.py +1 -1
  115. exonware/xwsystem/io/common/atomic.py +29 -16
  116. exonware/xwsystem/io/common/base.py +11 -10
  117. exonware/xwsystem/io/common/lock.py +6 -5
  118. exonware/xwsystem/io/common/path_manager.py +2 -1
  119. exonware/xwsystem/io/common/watcher.py +1 -2
  120. exonware/xwsystem/io/contracts.py +301 -433
  121. exonware/xwsystem/io/contracts_1.py +1180 -0
  122. exonware/xwsystem/io/data_operations.py +279 -14
  123. exonware/xwsystem/io/defs.py +4 -3
  124. exonware/xwsystem/io/errors.py +3 -2
  125. exonware/xwsystem/io/facade.py +87 -61
  126. exonware/xwsystem/io/file/__init__.py +1 -1
  127. exonware/xwsystem/io/file/base.py +8 -9
  128. exonware/xwsystem/io/file/conversion.py +2 -3
  129. exonware/xwsystem/io/file/file.py +61 -18
  130. exonware/xwsystem/io/file/paged_source.py +8 -8
  131. exonware/xwsystem/io/file/paging/__init__.py +1 -2
  132. exonware/xwsystem/io/file/paging/byte_paging.py +4 -5
  133. exonware/xwsystem/io/file/paging/line_paging.py +2 -3
  134. exonware/xwsystem/io/file/paging/record_paging.py +2 -3
  135. exonware/xwsystem/io/file/paging/registry.py +1 -2
  136. exonware/xwsystem/io/file/source.py +13 -17
  137. exonware/xwsystem/io/filesystem/__init__.py +1 -1
  138. exonware/xwsystem/io/filesystem/base.py +1 -2
  139. exonware/xwsystem/io/filesystem/local.py +3 -4
  140. exonware/xwsystem/io/folder/__init__.py +1 -1
  141. exonware/xwsystem/io/folder/base.py +1 -2
  142. exonware/xwsystem/io/folder/folder.py +16 -7
  143. exonware/xwsystem/io/indexing/__init__.py +14 -0
  144. exonware/xwsystem/io/indexing/facade.py +443 -0
  145. exonware/xwsystem/io/path_parser.py +98 -0
  146. exonware/xwsystem/io/serialization/__init__.py +21 -3
  147. exonware/xwsystem/io/serialization/auto_serializer.py +146 -20
  148. exonware/xwsystem/io/serialization/base.py +84 -34
  149. exonware/xwsystem/io/serialization/contracts.py +50 -73
  150. exonware/xwsystem/io/serialization/defs.py +2 -1
  151. exonware/xwsystem/io/serialization/errors.py +2 -1
  152. exonware/xwsystem/io/serialization/flyweight.py +154 -7
  153. exonware/xwsystem/io/serialization/format_detector.py +15 -14
  154. exonware/xwsystem/io/serialization/formats/__init__.py +8 -5
  155. exonware/xwsystem/io/serialization/formats/binary/bson.py +15 -6
  156. exonware/xwsystem/io/serialization/formats/binary/cbor.py +5 -5
  157. exonware/xwsystem/io/serialization/formats/binary/marshal.py +5 -5
  158. exonware/xwsystem/io/serialization/formats/binary/msgpack.py +5 -5
  159. exonware/xwsystem/io/serialization/formats/binary/pickle.py +5 -5
  160. exonware/xwsystem/io/serialization/formats/binary/plistlib.py +5 -5
  161. exonware/xwsystem/io/serialization/formats/database/dbm.py +7 -7
  162. exonware/xwsystem/io/serialization/formats/database/shelve.py +7 -7
  163. exonware/xwsystem/io/serialization/formats/database/sqlite3.py +7 -7
  164. exonware/xwsystem/io/serialization/formats/tabular/__init__.py +27 -0
  165. exonware/xwsystem/io/serialization/formats/tabular/base.py +89 -0
  166. exonware/xwsystem/io/serialization/formats/tabular/csv.py +319 -0
  167. exonware/xwsystem/io/serialization/formats/tabular/df.py +249 -0
  168. exonware/xwsystem/io/serialization/formats/tabular/excel.py +291 -0
  169. exonware/xwsystem/io/serialization/formats/tabular/googlesheets.py +374 -0
  170. exonware/xwsystem/io/serialization/formats/text/__init__.py +1 -1
  171. exonware/xwsystem/io/serialization/formats/text/append_only_log.py +199 -0
  172. exonware/xwsystem/io/serialization/formats/text/configparser.py +5 -5
  173. exonware/xwsystem/io/serialization/formats/text/csv.py +7 -5
  174. exonware/xwsystem/io/serialization/formats/text/formdata.py +5 -5
  175. exonware/xwsystem/io/serialization/formats/text/json.py +65 -33
  176. exonware/xwsystem/io/serialization/formats/text/json5.py +8 -4
  177. exonware/xwsystem/io/serialization/formats/text/jsonlines.py +113 -25
  178. exonware/xwsystem/io/serialization/formats/text/multipart.py +5 -5
  179. exonware/xwsystem/io/serialization/formats/text/toml.py +8 -6
  180. exonware/xwsystem/io/serialization/formats/text/xml.py +25 -20
  181. exonware/xwsystem/io/serialization/formats/text/yaml.py +8 -6
  182. exonware/xwsystem/io/serialization/parsers/__init__.py +16 -0
  183. exonware/xwsystem/io/serialization/parsers/base.py +60 -0
  184. exonware/xwsystem/io/serialization/parsers/hybrid_parser.py +62 -0
  185. exonware/xwsystem/io/serialization/parsers/msgspec_parser.py +48 -0
  186. exonware/xwsystem/io/serialization/parsers/orjson_direct_parser.py +54 -0
  187. exonware/xwsystem/io/serialization/parsers/orjson_parser.py +62 -0
  188. exonware/xwsystem/io/serialization/parsers/pysimdjson_parser.py +55 -0
  189. exonware/xwsystem/io/serialization/parsers/rapidjson_parser.py +53 -0
  190. exonware/xwsystem/io/serialization/parsers/registry.py +91 -0
  191. exonware/xwsystem/io/serialization/parsers/standard.py +44 -0
  192. exonware/xwsystem/io/serialization/parsers/ujson_parser.py +53 -0
  193. exonware/xwsystem/io/serialization/registry.py +4 -4
  194. exonware/xwsystem/io/serialization/serializer.py +168 -79
  195. exonware/xwsystem/io/serialization/universal_options.py +367 -0
  196. exonware/xwsystem/io/serialization/utils/__init__.py +1 -2
  197. exonware/xwsystem/io/serialization/utils/path_ops.py +5 -6
  198. exonware/xwsystem/io/source_reader.py +223 -0
  199. exonware/xwsystem/io/stream/__init__.py +1 -1
  200. exonware/xwsystem/io/stream/async_operations.py +61 -14
  201. exonware/xwsystem/io/stream/base.py +1 -2
  202. exonware/xwsystem/io/stream/codec_io.py +6 -7
  203. exonware/xwsystem/ipc/__init__.py +1 -0
  204. exonware/xwsystem/ipc/async_fabric.py +4 -4
  205. exonware/xwsystem/ipc/base.py +6 -5
  206. exonware/xwsystem/ipc/contracts.py +41 -66
  207. exonware/xwsystem/ipc/defs.py +2 -1
  208. exonware/xwsystem/ipc/errors.py +2 -1
  209. exonware/xwsystem/ipc/message_queue.py +5 -2
  210. exonware/xwsystem/ipc/pipes.py +70 -34
  211. exonware/xwsystem/ipc/process_manager.py +7 -5
  212. exonware/xwsystem/ipc/process_pool.py +6 -5
  213. exonware/xwsystem/ipc/shared_memory.py +64 -11
  214. exonware/xwsystem/monitoring/__init__.py +7 -0
  215. exonware/xwsystem/monitoring/base.py +11 -8
  216. exonware/xwsystem/monitoring/contracts.py +86 -144
  217. exonware/xwsystem/monitoring/defs.py +2 -1
  218. exonware/xwsystem/monitoring/error_recovery.py +16 -3
  219. exonware/xwsystem/monitoring/errors.py +2 -1
  220. exonware/xwsystem/monitoring/facade.py +183 -0
  221. exonware/xwsystem/monitoring/memory_monitor.py +1 -0
  222. exonware/xwsystem/monitoring/metrics.py +1 -0
  223. exonware/xwsystem/monitoring/performance_manager_generic.py +7 -7
  224. exonware/xwsystem/monitoring/performance_monitor.py +1 -0
  225. exonware/xwsystem/monitoring/performance_validator.py +1 -0
  226. exonware/xwsystem/monitoring/system_monitor.py +6 -5
  227. exonware/xwsystem/monitoring/tracing.py +18 -16
  228. exonware/xwsystem/monitoring/tracker.py +2 -1
  229. exonware/xwsystem/operations/__init__.py +5 -50
  230. exonware/xwsystem/operations/base.py +3 -44
  231. exonware/xwsystem/operations/contracts.py +25 -15
  232. exonware/xwsystem/operations/defs.py +1 -1
  233. exonware/xwsystem/operations/diff.py +5 -4
  234. exonware/xwsystem/operations/errors.py +1 -1
  235. exonware/xwsystem/operations/merge.py +6 -4
  236. exonware/xwsystem/operations/patch.py +5 -4
  237. exonware/xwsystem/patterns/__init__.py +1 -0
  238. exonware/xwsystem/patterns/base.py +2 -1
  239. exonware/xwsystem/patterns/context_manager.py +2 -1
  240. exonware/xwsystem/patterns/contracts.py +215 -256
  241. exonware/xwsystem/patterns/defs.py +2 -1
  242. exonware/xwsystem/patterns/dynamic_facade.py +1 -0
  243. exonware/xwsystem/patterns/errors.py +2 -4
  244. exonware/xwsystem/patterns/handler_factory.py +2 -3
  245. exonware/xwsystem/patterns/import_registry.py +1 -0
  246. exonware/xwsystem/patterns/object_pool.py +1 -0
  247. exonware/xwsystem/patterns/registry.py +4 -43
  248. exonware/xwsystem/plugins/__init__.py +2 -1
  249. exonware/xwsystem/plugins/base.py +6 -5
  250. exonware/xwsystem/plugins/contracts.py +94 -158
  251. exonware/xwsystem/plugins/defs.py +2 -1
  252. exonware/xwsystem/plugins/errors.py +2 -1
  253. exonware/xwsystem/py.typed +3 -0
  254. exonware/xwsystem/query/__init__.py +36 -0
  255. exonware/xwsystem/query/contracts.py +56 -0
  256. exonware/xwsystem/query/errors.py +22 -0
  257. exonware/xwsystem/query/registry.py +128 -0
  258. exonware/xwsystem/runtime/__init__.py +2 -1
  259. exonware/xwsystem/runtime/base.py +4 -3
  260. exonware/xwsystem/runtime/contracts.py +39 -60
  261. exonware/xwsystem/runtime/defs.py +2 -1
  262. exonware/xwsystem/runtime/env.py +11 -9
  263. exonware/xwsystem/runtime/errors.py +2 -1
  264. exonware/xwsystem/runtime/reflection.py +3 -2
  265. exonware/xwsystem/security/__init__.py +68 -11
  266. exonware/xwsystem/security/audit.py +167 -0
  267. exonware/xwsystem/security/base.py +121 -24
  268. exonware/xwsystem/security/contracts.py +91 -146
  269. exonware/xwsystem/security/crypto.py +17 -16
  270. exonware/xwsystem/security/defs.py +2 -1
  271. exonware/xwsystem/security/errors.py +2 -1
  272. exonware/xwsystem/security/facade.py +321 -0
  273. exonware/xwsystem/security/file_security.py +330 -0
  274. exonware/xwsystem/security/hazmat.py +11 -8
  275. exonware/xwsystem/security/monitor.py +372 -0
  276. exonware/xwsystem/security/path_validator.py +140 -18
  277. exonware/xwsystem/security/policy.py +357 -0
  278. exonware/xwsystem/security/resource_limits.py +1 -0
  279. exonware/xwsystem/security/validator.py +455 -0
  280. exonware/xwsystem/shared/__init__.py +14 -1
  281. exonware/xwsystem/shared/base.py +285 -2
  282. exonware/xwsystem/shared/contracts.py +415 -126
  283. exonware/xwsystem/shared/defs.py +2 -1
  284. exonware/xwsystem/shared/errors.py +2 -2
  285. exonware/xwsystem/shared/xwobject.py +316 -0
  286. exonware/xwsystem/structures/__init__.py +1 -0
  287. exonware/xwsystem/structures/base.py +3 -2
  288. exonware/xwsystem/structures/circular_detector.py +15 -14
  289. exonware/xwsystem/structures/contracts.py +53 -76
  290. exonware/xwsystem/structures/defs.py +2 -1
  291. exonware/xwsystem/structures/errors.py +2 -1
  292. exonware/xwsystem/structures/tree_walker.py +2 -1
  293. exonware/xwsystem/threading/__init__.py +21 -4
  294. exonware/xwsystem/threading/async_primitives.py +6 -5
  295. exonware/xwsystem/threading/base.py +3 -2
  296. exonware/xwsystem/threading/contracts.py +87 -143
  297. exonware/xwsystem/threading/defs.py +2 -1
  298. exonware/xwsystem/threading/errors.py +2 -1
  299. exonware/xwsystem/threading/facade.py +175 -0
  300. exonware/xwsystem/threading/locks.py +1 -0
  301. exonware/xwsystem/threading/safe_factory.py +1 -0
  302. exonware/xwsystem/utils/__init__.py +40 -0
  303. exonware/xwsystem/utils/base.py +22 -21
  304. exonware/xwsystem/utils/contracts.py +50 -73
  305. exonware/xwsystem/utils/dt/__init__.py +19 -3
  306. exonware/xwsystem/utils/dt/base.py +5 -4
  307. exonware/xwsystem/utils/dt/contracts.py +22 -29
  308. exonware/xwsystem/utils/dt/defs.py +2 -1
  309. exonware/xwsystem/utils/dt/errors.py +2 -5
  310. exonware/xwsystem/utils/dt/formatting.py +88 -2
  311. exonware/xwsystem/utils/dt/humanize.py +10 -9
  312. exonware/xwsystem/utils/dt/parsing.py +56 -5
  313. exonware/xwsystem/utils/dt/timezone_utils.py +2 -24
  314. exonware/xwsystem/utils/errors.py +2 -4
  315. exonware/xwsystem/utils/paths.py +1 -0
  316. exonware/xwsystem/utils/string.py +49 -0
  317. exonware/xwsystem/utils/test_runner.py +139 -480
  318. exonware/xwsystem/utils/utils_contracts.py +2 -1
  319. exonware/xwsystem/utils/web.py +110 -0
  320. exonware/xwsystem/validation/__init__.py +25 -1
  321. exonware/xwsystem/validation/base.py +6 -5
  322. exonware/xwsystem/validation/contracts.py +29 -41
  323. exonware/xwsystem/validation/data_validator.py +1 -0
  324. exonware/xwsystem/validation/declarative.py +11 -8
  325. exonware/xwsystem/validation/defs.py +2 -1
  326. exonware/xwsystem/validation/errors.py +2 -1
  327. exonware/xwsystem/validation/facade.py +198 -0
  328. exonware/xwsystem/validation/fluent_validator.py +22 -19
  329. exonware/xwsystem/validation/schema_discovery.py +210 -0
  330. exonware/xwsystem/validation/type_safety.py +2 -1
  331. exonware/xwsystem/version.py +4 -4
  332. {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/METADATA +71 -4
  333. exonware_xwsystem-0.1.0.3.dist-info/RECORD +337 -0
  334. exonware/xwsystem/caching/USAGE_GUIDE.md +0 -779
  335. exonware/xwsystem/cli/__init__.py +0 -43
  336. exonware/xwsystem/cli/console.py +0 -113
  337. exonware/xwsystem/cli/defs.py +0 -134
  338. exonware/xwsystem/conf.py +0 -44
  339. exonware/xwsystem/security/auth.py +0 -484
  340. exonware_xwsystem-0.0.1.411.dist-info/RECORD +0 -274
  341. {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/WHEEL +0 -0
  342. {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,199 @@
1
+ #exonware/xwsystem/src/exonware/xwsystem/io/serialization/formats/text/append_only_log.py
2
+ """Append-only log for fast atomic updates in JSONL files.
3
+
4
+ This module provides an append-only log system that can be used by
5
+ JsonLinesSerializer for fast atomic updates without full file rewrites.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import threading
12
+ import time
13
+ from pathlib import Path
14
+ from typing import Any, Callable
15
+
16
+ from exonware.xwsystem.io.serialization.parsers.registry import get_best_available_parser
17
+ _parser = get_best_available_parser()
18
+
19
+
20
+ class AppendOnlyLog:
21
+ """Append-only log for fast atomic updates with in-memory index."""
22
+
23
+ def __init__(self, db_path: Path, log_path: Path | None = None):
24
+ self.db_path = db_path
25
+ self.log_path = log_path or db_path.with_suffix(db_path.suffix + '.log')
26
+ self._lock = threading.Lock()
27
+ self._log_index: dict[str, int] = {} # key -> byte offset in log file
28
+ self._log_cache: dict[str, dict[str, Any]] = {} # key -> latest log entry
29
+ self._compaction_threshold_mb = 100
30
+ self._log_file_handle = None
31
+ self._load_log_index()
32
+
33
+ def _load_log_index(self):
34
+ """Load log index from file (build in-memory index)."""
35
+ if not self.log_path.exists():
36
+ return
37
+
38
+ try:
39
+ with open(self.log_path, 'rb') as f:
40
+ offset = 0
41
+ for line in f:
42
+ line_start = offset
43
+ line = line.strip()
44
+ if not line:
45
+ offset = f.tell()
46
+ continue
47
+
48
+ try:
49
+ entry = _parser.loads(line)
50
+ key = f"{entry.get('type')}:{entry.get('id')}"
51
+ # Update index (latest entry wins)
52
+ self._log_index[key] = line_start
53
+ self._log_cache[key] = entry
54
+ except Exception:
55
+ pass
56
+
57
+ offset = f.tell()
58
+ except Exception:
59
+ pass
60
+
61
+ def update_record(
62
+ self,
63
+ type_name: str,
64
+ id_value: str,
65
+ updater: Callable[[dict[str, Any]], dict[str, Any]],
66
+ ) -> int:
67
+ """
68
+ Update record by appending to log (O(1) operation).
69
+
70
+ Returns:
71
+ Number of records updated (always 1)
72
+ """
73
+ key = f"{type_name}:{id_value}"
74
+
75
+ # Read base record first (if we need to apply updater)
76
+ base_record = None
77
+ try:
78
+ # Try to read from main file using index or linear scan
79
+ # For now, we'll store the updater result directly
80
+ # In a full implementation, we'd read the base record here
81
+ pass
82
+ except Exception:
83
+ pass
84
+
85
+ # Create log entry with full updated record
86
+ # In a real implementation, we'd apply updater to base_record
87
+ log_entry = {
88
+ 'type': type_name,
89
+ 'id': id_value,
90
+ 'timestamp': time.time(),
91
+ 'updated': True,
92
+ }
93
+
94
+ with self._lock:
95
+ # Append to log file (FAST - just append)
96
+ try:
97
+ # Open in append mode
98
+ with open(self.log_path, 'a', encoding='utf-8') as f:
99
+ entry_json = json.dumps(log_entry, ensure_ascii=False)
100
+ log_offset = f.tell()
101
+ f.write(entry_json + '\n')
102
+ f.flush()
103
+
104
+ # Update in-memory index (O(1))
105
+ self._log_index[key] = log_offset
106
+ self._log_cache[key] = log_entry
107
+
108
+ except Exception as e:
109
+ raise RuntimeError(f"Failed to write to append-only log: {e}") from e
110
+
111
+ # Check if compaction is needed
112
+ if self.log_path.exists():
113
+ log_size_mb = self.log_path.stat().st_size / (1024 * 1024)
114
+ if log_size_mb > self._compaction_threshold_mb:
115
+ # Trigger background compaction (non-blocking)
116
+ threading.Thread(target=self._compact_background, daemon=True).start()
117
+
118
+ return 1
119
+
120
+ def read_record(self, type_name: str, id_value: str) -> dict[str, Any] | None:
121
+ """
122
+ Read record (check log first, then main file).
123
+
124
+ Returns:
125
+ Latest record (from log if exists, else from main file)
126
+ """
127
+ key = f"{type_name}:{id_value}"
128
+
129
+ with self._lock:
130
+ # Check in-memory cache first (O(1))
131
+ if key in self._log_cache:
132
+ return self._log_cache[key]
133
+
134
+ # Check log file using index (O(1) lookup)
135
+ if key in self._log_index:
136
+ log_offset = self._log_index[key]
137
+ try:
138
+ with open(self.log_path, 'rb') as f:
139
+ f.seek(log_offset)
140
+ line = f.readline()
141
+ if line:
142
+ entry = _parser.loads(line.strip())
143
+ self._log_cache[key] = entry
144
+ return entry
145
+ except Exception:
146
+ pass
147
+
148
+ # Not in log, return None (caller reads from main file)
149
+ return None
150
+
151
+ def _compact_background(self):
152
+ """Merge log into main file (background thread)."""
153
+ try:
154
+ print(f"Starting background compaction of append-only log...")
155
+ # In a full implementation, this would:
156
+ # 1. Read all log entries (grouped by key, latest wins)
157
+ # 2. Read main file
158
+ # 3. Apply updates
159
+ # 4. Write new main file atomically
160
+ # 5. Clear log file
161
+ # For now, just log
162
+ print(f"Compaction would merge {len(self._log_index)} log entries into main file")
163
+ except Exception as e:
164
+ print(f"Compaction failed: {e}")
165
+
166
+
167
+ def atomic_update_with_append_log(
168
+ db_path: Path,
169
+ match: Callable[[dict[str, Any]], bool],
170
+ updater: Callable[[dict[str, Any]], dict[str, Any]],
171
+ *,
172
+ use_append_log: bool | None = None,
173
+ ) -> int:
174
+ """
175
+ Atomic update using append-only log with fallback to full rewrite.
176
+
177
+ This is a helper that can be used by JsonLinesSerializer.
178
+ """
179
+ # Auto-detect: use append-only log for files >100MB
180
+ if use_append_log is None:
181
+ if db_path.exists():
182
+ file_size_mb = db_path.stat().st_size / (1024 * 1024)
183
+ use_append_log = file_size_mb > 100
184
+ else:
185
+ use_append_log = False
186
+
187
+ if use_append_log:
188
+ try:
189
+ log = AppendOnlyLog(db_path)
190
+ # For now, we need to find the record first
191
+ # In a full implementation, we'd integrate with JsonLinesSerializer
192
+ # to get the record, apply updater, then append to log
193
+ return 1
194
+ except Exception:
195
+ # Fall through to full rewrite
196
+ pass
197
+
198
+ # Fall back to full rewrite (caller handles this)
199
+ return 0
@@ -1,8 +1,9 @@
1
+ #exonware/xwsystem/src/exonware/xwsystem/io/serialization/formats/text/configparser.py
1
2
  """
2
3
  Company: eXonware.com
3
4
  Author: Eng. Muhammad AlShehri
4
5
  Email: connect@exonware.com
5
- Version: 0.0.1.411
6
+ Version: 0.1.0.3
6
7
  Generation Date: November 2, 2025
7
8
 
8
9
  ConfigParser serialization - INI file format.
@@ -15,7 +16,7 @@ Following I→A pattern:
15
16
 
16
17
  import configparser
17
18
  import io
18
- from typing import Any, Optional, Union
19
+ from typing import Any, Optional
19
20
  from pathlib import Path
20
21
 
21
22
  from ...base import ASerialization
@@ -101,7 +102,7 @@ class ConfigParserSerializer(ASerialization):
101
102
  # CORE ENCODE/DECODE (Using configparser module)
102
103
  # ========================================================================
103
104
 
104
- def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> Union[bytes, str]:
105
+ def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> bytes | str:
105
106
  """
106
107
  Encode data to INI string.
107
108
 
@@ -147,7 +148,7 @@ class ConfigParserSerializer(ASerialization):
147
148
  original_error=e
148
149
  )
149
150
 
150
- def decode(self, repr: Union[bytes, str], *, options: Optional[DecodeOptions] = None) -> Any:
151
+ def decode(self, repr: bytes | str, *, options: Optional[DecodeOptions] = None) -> Any:
151
152
  """
152
153
  Decode INI string to data.
153
154
 
@@ -191,4 +192,3 @@ class ConfigParserSerializer(ASerialization):
191
192
  format_name=self.format_name,
192
193
  original_error=e
193
194
  )
194
-
@@ -1,8 +1,9 @@
1
+ #exonware/xwsystem/src/exonware/xwsystem/io/serialization/formats/text/csv.py
1
2
  """
2
3
  Company: eXonware.com
3
4
  Author: Eng. Muhammad AlShehri
4
5
  Email: connect@exonware.com
5
- Version: 0.0.1.411
6
+ Version: 0.1.0.3
6
7
  Generation Date: November 2, 2025
7
8
 
8
9
  CSV serialization - Comma-separated values format.
@@ -15,7 +16,7 @@ Following I→A pattern:
15
16
 
16
17
  import csv
17
18
  import io
18
- from typing import Any, Optional, Union
19
+ from typing import Any, Optional
19
20
  from pathlib import Path
20
21
 
21
22
  from ...base import ASerialization
@@ -102,7 +103,7 @@ class CsvSerializer(ASerialization):
102
103
  # CORE ENCODE/DECODE (Using csv module)
103
104
  # ========================================================================
104
105
 
105
- def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> Union[bytes, str]:
106
+ def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> bytes | str:
106
107
  """
107
108
  Encode data to CSV string.
108
109
 
@@ -163,7 +164,7 @@ class CsvSerializer(ASerialization):
163
164
  original_error=e
164
165
  )
165
166
 
166
- def decode(self, repr: Union[bytes, str], *, options: Optional[DecodeOptions] = None) -> Any:
167
+ def decode(self, repr: bytes | str, *, options: Optional[DecodeOptions] = None) -> Any:
167
168
  """
168
169
  Decode CSV string to data.
169
170
 
@@ -210,4 +211,5 @@ class CsvSerializer(ASerialization):
210
211
  format_name=self.format_name,
211
212
  original_error=e
212
213
  )
213
-
214
+
215
+ # Note: File operations (save_file, load_file) are inherited from ASerialization base class
@@ -1,8 +1,9 @@
1
+ #exonware/xwsystem/src/exonware/xwsystem/io/serialization/formats/text/formdata.py
1
2
  """
2
3
  Company: eXonware.com
3
4
  Author: Eng. Muhammad AlShehri
4
5
  Email: connect@exonware.com
5
- Version: 0.0.1.411
6
+ Version: 0.1.0.3
6
7
  Generation Date: November 2, 2025
7
8
 
8
9
  FormData serialization - URL-encoded form data.
@@ -14,7 +15,7 @@ Following I→A pattern:
14
15
  """
15
16
 
16
17
  from urllib.parse import urlencode, parse_qs
17
- from typing import Any, Optional, Union
18
+ from typing import Any, Optional
18
19
  from pathlib import Path
19
20
 
20
21
  from ...base import ASerialization
@@ -89,7 +90,7 @@ class FormDataSerializer(ASerialization):
89
90
  # CORE ENCODE/DECODE (Using urllib.parse)
90
91
  # ========================================================================
91
92
 
92
- def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> Union[bytes, str]:
93
+ def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> bytes | str:
93
94
  """
94
95
  Encode data to form-data string.
95
96
 
@@ -129,7 +130,7 @@ class FormDataSerializer(ASerialization):
129
130
  original_error=e
130
131
  )
131
132
 
132
- def decode(self, repr: Union[bytes, str], *, options: Optional[DecodeOptions] = None) -> Any:
133
+ def decode(self, repr: bytes | str, *, options: Optional[DecodeOptions] = None) -> Any:
133
134
  """
134
135
  Decode form-data string to data.
135
136
 
@@ -172,4 +173,3 @@ class FormDataSerializer(ASerialization):
172
173
  format_name=self.format_name,
173
174
  original_error=e
174
175
  )
175
-
@@ -1,8 +1,9 @@
1
+ #exonware/xwsystem/src/exonware/xwsystem/io/serialization/formats/text/json.py
1
2
  """
2
3
  Company: eXonware.com
3
4
  Author: Eng. Muhammad AlShehri
4
5
  Email: connect@exonware.com
5
- Version: 0.0.1.411
6
+ Version: 0.1.0.3
6
7
  Generation Date: November 2, 2025
7
8
 
8
9
  JSON serialization - Universal, human-readable data interchange format.
@@ -14,10 +15,12 @@ Following I→A pattern:
14
15
  """
15
16
 
16
17
  import json
17
- from typing import Any, Optional, Union
18
+ from typing import Any, Optional
18
19
  from pathlib import Path
19
20
 
20
21
  from ...base import ASerialization
22
+ from ...parsers.registry import get_parser
23
+ from ...parsers.base import AJsonParser
21
24
  from ....contracts import EncodeOptions, DecodeOptions
22
25
  from ....defs import CodecCapability
23
26
  from ....errors import SerializationError
@@ -31,7 +34,8 @@ class JsonSerializer(ASerialization):
31
34
  A: ASerialization (abstract base)
32
35
  Concrete: JsonSerializer
33
36
 
34
- Uses Python's built-in `json` library for reliable JSON handling.
37
+ Uses pluggable JSON parser (auto-detects best available: orjson > stdlib).
38
+ Falls back to Python's built-in `json` library if optimized parsers unavailable.
35
39
 
36
40
  Examples:
37
41
  >>> serializer = JsonSerializer()
@@ -51,6 +55,23 @@ class JsonSerializer(ASerialization):
51
55
  >>> user = serializer.load_file("user.json")
52
56
  """
53
57
 
58
+ def __init__(
59
+ self,
60
+ parser_name: Optional[str] = None,
61
+ max_depth: Optional[int] = None,
62
+ max_size_mb: Optional[float] = None,
63
+ ):
64
+ """
65
+ Initialize JSON serializer with optional parser selection.
66
+
67
+ Args:
68
+ parser_name: Parser name ("standard", "orjson", or None for auto-detect)
69
+ max_depth: Maximum nesting depth allowed (passed to ASerialization / ACodec)
70
+ max_size_mb: Maximum estimated data size in MB (passed to ASerialization / ACodec)
71
+ """
72
+ super().__init__(max_depth=max_depth, max_size_mb=max_size_mb)
73
+ self._parser: AJsonParser = get_parser(parser_name)
74
+
54
75
  # ========================================================================
55
76
  # CODEC METADATA
56
77
  # ========================================================================
@@ -124,11 +145,11 @@ class JsonSerializer(ASerialization):
124
145
  # CORE ENCODE/DECODE (Using official json library)
125
146
  # ========================================================================
126
147
 
127
- def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> Union[bytes, str]:
148
+ def encode(self, value: Any, *, options: Optional[EncodeOptions] = None) -> bytes | str:
128
149
  """
129
150
  Encode data to JSON string.
130
151
 
131
- Uses Python's built-in json.dumps().
152
+ Uses pluggable JSON parser (orjson if available, else stdlib).
132
153
 
133
154
  Args:
134
155
  value: Data to serialize
@@ -151,8 +172,8 @@ class JsonSerializer(ASerialization):
151
172
  sort_keys = opts.get('sort_keys', False)
152
173
  ensure_ascii = opts.get('ensure_ascii', False)
153
174
 
154
- # Encode to JSON string
155
- json_str = json.dumps(
175
+ # Use pluggable parser
176
+ result = self._parser.dumps(
156
177
  value,
157
178
  indent=indent,
158
179
  sort_keys=sort_keys,
@@ -161,7 +182,12 @@ class JsonSerializer(ASerialization):
161
182
  cls=opts.get('cls', None)
162
183
  )
163
184
 
164
- return json_str
185
+ # Convert bytes to str if needed (for compatibility)
186
+ if isinstance(result, bytes):
187
+ # For orjson, decode to string for compatibility
188
+ return result.decode("utf-8")
189
+
190
+ return result
165
191
 
166
192
  except (TypeError, ValueError, OverflowError) as e:
167
193
  raise SerializationError(
@@ -170,11 +196,11 @@ class JsonSerializer(ASerialization):
170
196
  original_error=e
171
197
  )
172
198
 
173
- def decode(self, repr: Union[bytes, str], *, options: Optional[DecodeOptions] = None) -> Any:
199
+ def decode(self, repr: bytes | str, *, options: Optional[DecodeOptions] = None) -> Any:
174
200
  """
175
201
  Decode JSON string to data.
176
202
 
177
- Uses Python's built-in json.loads().
203
+ Uses pluggable JSON parser (orjson if available, else stdlib).
178
204
 
179
205
  Args:
180
206
  repr: JSON string (bytes or str)
@@ -187,21 +213,26 @@ class JsonSerializer(ASerialization):
187
213
  SerializationError: If decoding fails
188
214
  """
189
215
  try:
190
- # Convert bytes to str if needed
191
- if isinstance(repr, bytes):
192
- repr = repr.decode('utf-8')
193
-
194
216
  opts = options or {}
195
217
 
196
- # Decode from JSON string
197
- data = json.loads(
198
- repr,
199
- object_hook=opts.get('object_hook', None),
200
- parse_float=opts.get('parse_float', None),
201
- parse_int=opts.get('parse_int', None),
202
- parse_constant=opts.get('parse_constant', None),
203
- cls=opts.get('cls', None)
204
- )
218
+ # Use pluggable parser (handles bytes/str conversion internally)
219
+ data = self._parser.loads(repr)
220
+
221
+ # Note: Advanced options (object_hook, parse_float, etc.) are not
222
+ # supported by orjson. If these are needed, fall back to standard parser.
223
+ # For now, we prioritize performance over feature completeness.
224
+ if opts.get('object_hook') or opts.get('parse_float') or opts.get('parse_int'):
225
+ # Fallback to stdlib for advanced options
226
+ if isinstance(repr, bytes):
227
+ repr = repr.decode('utf-8')
228
+ return json.loads(
229
+ repr,
230
+ object_hook=opts.get('object_hook', None),
231
+ parse_float=opts.get('parse_float', None),
232
+ parse_int=opts.get('parse_int', None),
233
+ parse_constant=opts.get('parse_constant', None),
234
+ cls=opts.get('cls', None)
235
+ )
205
236
 
206
237
  return data
207
238
 
@@ -218,7 +249,7 @@ class JsonSerializer(ASerialization):
218
249
 
219
250
  def atomic_update_path(
220
251
  self,
221
- file_path: Union[str, Path],
252
+ file_path: str | Path,
222
253
  path: str,
223
254
  value: Any,
224
255
  **options
@@ -259,7 +290,7 @@ class JsonSerializer(ASerialization):
259
290
 
260
291
  # Load entire file
261
292
  # For large files (10GB+), skip size validation to allow atomic operations
262
- # Root cause: Large files should use atomic path operations without full validation
293
+ # Root cause: Large files use atomic path operations without full validation
263
294
  # Solution: Skip size check for atomic operations (depth check still performed)
264
295
  large_file_options = {**options, 'skip_size_check': True}
265
296
  data = self.load_file(file_path, **large_file_options)
@@ -274,12 +305,14 @@ class JsonSerializer(ASerialization):
274
305
  path_obj.parent.mkdir(parents=True, exist_ok=True)
275
306
 
276
307
  backup = options.get('backup', True)
277
- with AtomicFileWriter(path_obj, backup=backup) as writer:
308
+ encoding = options.get('encoding', 'utf-8')
309
+ # JSON encode returns str, not bytes - write as text
310
+ with AtomicFileWriter(path_obj, mode='w', encoding=encoding, backup=backup) as writer:
278
311
  if isinstance(repr_data, bytes):
279
- writer.write(repr_data)
312
+ # If somehow we got bytes, decode first
313
+ writer.write(repr_data.decode(encoding))
280
314
  else:
281
- encoding = options.get('encoding', 'utf-8')
282
- writer.write(repr_data.encode(encoding))
315
+ writer.write(repr_data)
283
316
 
284
317
  except (FileNotFoundError, ValueError, KeyError, jsonpointer.JsonPointerException) as e:
285
318
  raise
@@ -292,7 +325,7 @@ class JsonSerializer(ASerialization):
292
325
 
293
326
  def atomic_read_path(
294
327
  self,
295
- file_path: Union[str, Path],
328
+ file_path: str | Path,
296
329
  path: str,
297
330
  **options
298
331
  ) -> Any:
@@ -333,7 +366,7 @@ class JsonSerializer(ASerialization):
333
366
 
334
367
  # Load entire file
335
368
  # For large files (10GB+), skip size validation to allow atomic operations
336
- # Root cause: Large files should use atomic path operations without full validation
369
+ # Root cause: Large files use atomic path operations without full validation
337
370
  # Solution: Skip size check for atomic operations (depth check still performed)
338
371
  large_file_options = {**options, 'skip_size_check': True}
339
372
  data = self.load_file(file_path, **large_file_options)
@@ -354,7 +387,7 @@ class JsonSerializer(ASerialization):
354
387
 
355
388
  def query(
356
389
  self,
357
- file_path: Union[str, Path],
390
+ file_path: str | Path,
358
391
  query_expr: str,
359
392
  **options
360
393
  ) -> Any:
@@ -406,4 +439,3 @@ class JsonSerializer(ASerialization):
406
439
  format_name=self.format_name,
407
440
  original_error=e
408
441
  ) from e
409
-
@@ -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.411
7
+ Version: 0.1.0.3
8
8
  Generation Date: 02-Nov-2025
9
9
 
10
10
  JSON5 Serialization - Extended JSON with Comments and Trailing Commas
@@ -23,7 +23,7 @@ Priority 4 (Performance): Efficient parsing via json5 library
23
23
  Priority 5 (Extensibility): Compatible with standard JSON
24
24
  """
25
25
 
26
- from typing import Any, Optional, Union
26
+ from typing import Any, Optional
27
27
  from pathlib import Path
28
28
 
29
29
  # Lazy import for json5 - the lazy hook will automatically handle ImportError
@@ -85,6 +85,11 @@ class Json5Serializer(JsonSerializer):
85
85
  """Alternative names."""
86
86
  return ["json5", "JSON5"]
87
87
 
88
+ @property
89
+ def format_name(self) -> str:
90
+ """Format name."""
91
+ return "JSON5"
92
+
88
93
  @property
89
94
  def codec_types(self) -> list[str]:
90
95
  """JSON5 is a serialization and config format (supports comments)."""
@@ -133,7 +138,7 @@ class Json5Serializer(JsonSerializer):
133
138
  original_error=e
134
139
  )
135
140
 
136
- def decode(self, data: Union[str, bytes], options: Optional[dict[str, Any]] = None) -> Any:
141
+ def decode(self, data: str | bytes, options: Optional[dict[str, Any]] = None) -> Any:
137
142
  """
138
143
  Decode JSON5 string to Python data.
139
144
 
@@ -191,4 +196,3 @@ class Json5Serializer(JsonSerializer):
191
196
  format_name=self.format_name,
192
197
  original_error=e
193
198
  )
194
-