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
@@ -1,15 +1,18 @@
1
+ #exonware/xwsystem/src/exonware/xwsystem/io/contracts.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: September 04, 2025
7
8
 
8
9
  IO module contracts - interfaces and enums for input/output operations.
9
10
  """
10
11
 
11
- from abc import ABC, abstractmethod
12
- from typing import Any, Optional, Union, AsyncGenerator, BinaryIO, TextIO, Protocol, runtime_checkable, Callable, Iterator
12
+ from __future__ import annotations
13
+
14
+ from typing import Protocol, runtime_checkable
15
+ from typing import Any, Optional, AsyncGenerator, BinaryIO, TextIO, Protocol, runtime_checkable, Callable, Iterator
13
16
  from typing_extensions import TypeAlias
14
17
  from pathlib import Path
15
18
 
@@ -36,7 +39,8 @@ from .defs import (
36
39
  # FILE INTERFACES
37
40
  # ============================================================================
38
41
 
39
- class IFile(ABC):
42
+ @runtime_checkable
43
+ class IFile(Protocol):
40
44
  """
41
45
  Interface for file operations with both static and instance methods.
42
46
 
@@ -51,234 +55,198 @@ class IFile(ABC):
51
55
  # INSTANCE METHODS
52
56
  # ============================================================================
53
57
 
54
- @abstractmethod
55
58
  def open(self, mode: FileMode = FileMode.READ) -> None:
56
59
  """Open file with specified mode."""
57
- pass
60
+ ...
58
61
 
59
- @abstractmethod
60
- def read(self, size: Optional[int] = None) -> Union[str, bytes]:
62
+ def read(self, size: Optional[int] = None) -> str | bytes:
61
63
  """Read from file."""
62
- pass
64
+ ...
63
65
 
64
- @abstractmethod
65
- def write(self, data: Union[str, bytes]) -> int:
66
+ def write(self, data: str | bytes) -> int:
66
67
  """Write to file."""
67
- pass
68
+ ...
68
69
 
69
- @abstractmethod
70
70
  def close(self) -> None:
71
71
  """Close file."""
72
- pass
72
+ ...
73
73
 
74
- @abstractmethod
75
74
  def save(self, data: Any, **kwargs) -> bool:
76
75
  """Save data to file."""
77
- pass
76
+ ...
78
77
 
79
- @abstractmethod
80
78
  def load(self, **kwargs) -> Any:
81
79
  """Load data from file."""
82
- pass
80
+ ...
83
81
 
84
- @abstractmethod
85
- def save_as(self, path: Union[str, Path], data: Any, **kwargs) -> bool:
82
+ def save_as(self, path: str | Path, data: Any, **kwargs) -> bool:
86
83
  """Save data to specific path."""
87
- pass
84
+ ...
88
85
 
89
- @abstractmethod
90
- def to_file(self, path: Union[str, Path], **kwargs) -> bool:
86
+ def to_file(self, path: str | Path, **kwargs) -> bool:
91
87
  """Write current object to file."""
92
- pass
88
+ ...
93
89
 
94
- @abstractmethod
95
- def from_file(self, path: Union[str, Path], **kwargs) -> 'IFile':
90
+ def from_file(self, path: str | Path, **kwargs) -> IFile:
96
91
  """Load object from file."""
97
- pass
92
+ ...
98
93
 
99
94
  # ============================================================================
100
95
  # STATIC METHODS
101
96
  # ============================================================================
102
97
 
103
98
  @staticmethod
104
- @abstractmethod
105
- def exists(path: Union[str, Path]) -> bool:
99
+ def exists(path: str | Path) -> bool:
106
100
  """Check if file exists."""
107
- pass
101
+ ...
108
102
 
109
103
  @staticmethod
110
- @abstractmethod
111
- def size(path: Union[str, Path]) -> int:
104
+ def size(path: str | Path) -> int:
112
105
  """Get file size."""
113
- pass
106
+ ...
114
107
 
115
108
  @staticmethod
116
- @abstractmethod
117
- def delete(path: Union[str, Path]) -> bool:
109
+ def delete(path: str | Path) -> bool:
118
110
  """Delete file."""
119
- pass
111
+ ...
120
112
 
121
113
  @staticmethod
122
- @abstractmethod
123
- def copy(source: Union[str, Path], destination: Union[str, Path]) -> bool:
114
+ def copy(source: str | Path, destination: str | Path) -> bool:
124
115
  """Copy file."""
125
- pass
116
+ ...
126
117
 
127
118
  @staticmethod
128
- @abstractmethod
129
- def move(source: Union[str, Path], destination: Union[str, Path]) -> bool:
119
+ def move(source: str | Path, destination: str | Path) -> bool:
130
120
  """Move file."""
131
- pass
121
+ ...
132
122
 
133
123
  @staticmethod
134
- @abstractmethod
135
- def rename(old_path: Union[str, Path], new_path: Union[str, Path]) -> bool:
124
+ def rename(old_path: str | Path, new_path: str | Path) -> bool:
136
125
  """Rename file."""
137
- pass
126
+ ...
138
127
 
139
128
  @staticmethod
140
- @abstractmethod
141
- def get_modified_time(path: Union[str, Path]) -> float:
129
+ def get_modified_time(path: str | Path) -> float:
142
130
  """Get file modification time."""
143
- pass
131
+ ...
144
132
 
145
133
  @staticmethod
146
- @abstractmethod
147
- def get_created_time(path: Union[str, Path]) -> float:
134
+ def get_created_time(path: str | Path) -> float:
148
135
  """Get file creation time."""
149
- pass
136
+ ...
150
137
 
151
138
  @staticmethod
152
- @abstractmethod
153
- def get_permissions(path: Union[str, Path]) -> int:
139
+ def get_permissions(path: str | Path) -> int:
154
140
  """Get file permissions."""
155
- pass
141
+ ...
156
142
 
157
143
  @staticmethod
158
- @abstractmethod
159
- def is_readable(path: Union[str, Path]) -> bool:
144
+ def is_readable(path: str | Path) -> bool:
160
145
  """Check if file is readable."""
161
- pass
146
+ ...
162
147
 
163
148
  @staticmethod
164
- @abstractmethod
165
- def is_writable(path: Union[str, Path]) -> bool:
149
+ def is_writable(path: str | Path) -> bool:
166
150
  """Check if file is writable."""
167
- pass
151
+ ...
168
152
 
169
153
  @staticmethod
170
- @abstractmethod
171
- def is_executable(path: Union[str, Path]) -> bool:
154
+ def is_executable(path: str | Path) -> bool:
172
155
  """Check if file is executable."""
173
- pass
156
+ ...
174
157
 
175
158
  @staticmethod
176
- @abstractmethod
177
- def read_text(path: Union[str, Path], encoding: str = 'utf-8') -> str:
159
+ def read_text(path: str | Path, encoding: str = 'utf-8') -> str:
178
160
  """Read file as text."""
179
- pass
161
+ ...
180
162
 
181
163
  @staticmethod
182
- @abstractmethod
183
- def read_bytes(path: Union[str, Path]) -> bytes:
164
+ def read_bytes(path: str | Path) -> bytes:
184
165
  """Read file as bytes."""
185
- pass
166
+ ...
186
167
 
187
168
  @staticmethod
188
- @abstractmethod
189
- def write_text(path: Union[str, Path], content: str, encoding: str = 'utf-8') -> bool:
169
+ def write_text(path: str | Path, content: str, encoding: str = 'utf-8') -> bool:
190
170
  """Write text to file."""
191
- pass
171
+ ...
192
172
 
193
173
  @staticmethod
194
- @abstractmethod
195
- def write_bytes(path: Union[str, Path], content: bytes) -> bool:
174
+ def write_bytes(path: str | Path, content: bytes) -> bool:
196
175
  """Write bytes to file."""
197
- pass
176
+ ...
198
177
 
199
178
  @staticmethod
200
- @abstractmethod
201
- def safe_read_text(path: Union[str, Path], encoding: str = 'utf-8') -> Optional[str]:
179
+ def safe_read_text(path: str | Path, encoding: str = 'utf-8') -> Optional[str]:
202
180
  """Safely read text file, returning None on error."""
203
- pass
181
+ ...
204
182
 
205
183
  @staticmethod
206
- @abstractmethod
207
- def safe_read_bytes(path: Union[str, Path]) -> Optional[bytes]:
184
+ def safe_read_bytes(path: str | Path) -> Optional[bytes]:
208
185
  """Safely read binary file, returning None on error."""
209
- pass
186
+ ...
210
187
 
211
188
  @staticmethod
212
- @abstractmethod
213
- def safe_write_text(path: Union[str, Path], content: str, encoding: str = 'utf-8') -> bool:
189
+ def safe_write_text(path: str | Path, content: str, encoding: str = 'utf-8') -> bool:
214
190
  """Safely write text to file."""
215
- pass
191
+ ...
216
192
 
217
193
  @staticmethod
218
- @abstractmethod
219
- def safe_write_bytes(path: Union[str, Path], content: bytes) -> bool:
194
+ def safe_write_bytes(path: str | Path, content: bytes) -> bool:
220
195
  """Safely write bytes to file."""
221
- pass
196
+ ...
222
197
 
223
198
  # ============================================================================
224
199
  # STATIC UTILITY METHODS (File Manager Features)
225
200
  # ============================================================================
226
201
 
227
202
  @staticmethod
228
- @abstractmethod
229
- def atomic_write(file_path: Union[str, Path], data: Union[str, bytes],
203
+ def atomic_write(file_path: str | Path, data: str | bytes,
230
204
  backup: bool = True) -> OperationResult:
231
205
  """Atomically write data to file (static version)."""
232
- pass
206
+ ...
233
207
 
234
208
  @staticmethod
235
- @abstractmethod
236
- def atomic_copy(source: Union[str, Path], destination: Union[str, Path]) -> OperationResult:
209
+ def atomic_copy(source: str | Path, destination: str | Path) -> OperationResult:
237
210
  """Atomically copy file (static version)."""
238
- pass
211
+ ...
239
212
 
240
213
  @staticmethod
241
- @abstractmethod
242
- def atomic_move(source: Union[str, Path], destination: Union[str, Path]) -> OperationResult:
214
+ def atomic_move(source: str | Path, destination: str | Path) -> OperationResult:
243
215
  """Atomically move file (static version)."""
244
- pass
216
+ ...
245
217
 
246
218
  @staticmethod
247
- @abstractmethod
248
- def atomic_delete(file_path: Union[str, Path], backup: bool = True) -> OperationResult:
219
+ def atomic_delete(file_path: str | Path, backup: bool = True) -> OperationResult:
249
220
  """Atomically delete file (static version)."""
250
- pass
221
+ ...
251
222
 
252
223
  @staticmethod
253
- @abstractmethod
254
- def create_backup(source: Union[str, Path], backup_dir: Union[str, Path]) -> Optional[Path]:
224
+ def create_backup(source: str | Path, backup_dir: str | Path) -> Optional[Path]:
255
225
  """Create backup of file (static version)."""
256
- pass
226
+ ...
257
227
 
258
228
  @staticmethod
259
- @abstractmethod
260
- def restore_backup(backup_path: Union[str, Path], target: Union[str, Path]) -> OperationResult:
229
+ def restore_backup(backup_path: str | Path, target: str | Path) -> OperationResult:
261
230
  """Restore from backup (static version)."""
262
- pass
231
+ ...
263
232
 
264
233
  @staticmethod
265
- @abstractmethod
266
234
  def create_temp_file(suffix: Optional[str] = None, prefix: Optional[str] = None) -> Path:
267
235
  """Create temporary file (static version)."""
268
- pass
236
+ ...
269
237
 
270
238
  @staticmethod
271
- @abstractmethod
272
239
  def create_temp_directory(suffix: Optional[str] = None, prefix: Optional[str] = None) -> Path:
273
240
  """Create temporary directory (static version)."""
274
- pass
241
+ ...
275
242
 
276
243
 
277
244
  # ============================================================================
278
245
  # FOLDER INTERFACES
279
246
  # ============================================================================
280
247
 
281
- class IFolder(ABC):
248
+ @runtime_checkable
249
+ class IFolder(Protocol):
282
250
  """
283
251
  Interface for folder/directory operations with both static and instance methods.
284
252
 
@@ -293,145 +261,123 @@ class IFolder(ABC):
293
261
  # INSTANCE METHODS
294
262
  # ============================================================================
295
263
 
296
- @abstractmethod
297
264
  def create(self, parents: bool = True, exist_ok: bool = True) -> bool:
298
265
  """Create directory."""
299
- pass
266
+ ...
300
267
 
301
- @abstractmethod
302
268
  def delete(self, recursive: bool = False) -> bool:
303
269
  """Delete directory."""
304
- pass
270
+ ...
305
271
 
306
- @abstractmethod
307
272
  def list_files(self, pattern: Optional[str] = None, recursive: bool = False) -> list[Path]:
308
273
  """List files in directory."""
309
- pass
274
+ ...
310
275
 
311
- @abstractmethod
312
276
  def list_directories(self, recursive: bool = False) -> list[Path]:
313
277
  """List subdirectories."""
314
- pass
278
+ ...
315
279
 
316
- @abstractmethod
317
280
  def walk(self) -> list[tuple[Path, list[str], list[str]]]:
318
281
  """Walk directory tree."""
319
- pass
282
+ ...
320
283
 
321
- @abstractmethod
322
284
  def get_size(self) -> int:
323
285
  """Get directory size."""
324
- pass
286
+ ...
325
287
 
326
- @abstractmethod
327
288
  def is_empty(self) -> bool:
328
289
  """Check if directory is empty."""
329
- pass
290
+ ...
330
291
 
331
- @abstractmethod
332
- def copy_to(self, destination: Union[str, Path]) -> bool:
292
+ def copy_to(self, destination: str | Path) -> bool:
333
293
  """Copy directory to destination."""
334
- pass
294
+ ...
335
295
 
336
- @abstractmethod
337
- def move_to(self, destination: Union[str, Path]) -> bool:
296
+ def move_to(self, destination: str | Path) -> bool:
338
297
  """Move directory to destination."""
339
- pass
298
+ ...
340
299
 
341
300
  # ============================================================================
342
301
  # STATIC METHODS
343
302
  # ============================================================================
344
303
 
345
304
  @staticmethod
346
- @abstractmethod
347
- def exists(path: Union[str, Path]) -> bool:
305
+ def exists(path: str | Path) -> bool:
348
306
  """Check if directory exists."""
349
- pass
307
+ ...
350
308
 
351
309
  @staticmethod
352
- @abstractmethod
353
- def create_dir(path: Union[str, Path], parents: bool = True, exist_ok: bool = True) -> bool:
310
+ def create_dir(path: str | Path, parents: bool = True, exist_ok: bool = True) -> bool:
354
311
  """Create directory."""
355
- pass
312
+ ...
356
313
 
357
314
  @staticmethod
358
- @abstractmethod
359
- def delete_dir(path: Union[str, Path], recursive: bool = False) -> bool:
315
+ def delete_dir(path: str | Path, recursive: bool = False) -> bool:
360
316
  """Delete directory."""
361
- pass
317
+ ...
362
318
 
363
319
  @staticmethod
364
- @abstractmethod
365
- def list_files_static(path: Union[str, Path], pattern: Optional[str] = None, recursive: bool = False) -> list[Path]:
320
+ def list_files_static(path: str | Path, pattern: Optional[str] = None, recursive: bool = False) -> list[Path]:
366
321
  """List files in directory."""
367
- pass
322
+ ...
368
323
 
369
324
  @staticmethod
370
- @abstractmethod
371
- def list_directories_static(path: Union[str, Path], recursive: bool = False) -> list[Path]:
325
+ def list_directories_static(path: str | Path, recursive: bool = False) -> list[Path]:
372
326
  """List subdirectories."""
373
- pass
327
+ ...
374
328
 
375
329
  @staticmethod
376
- @abstractmethod
377
- def walk_static(path: Union[str, Path]) -> list[tuple[Path, list[str], list[str]]]:
330
+ def walk_static(path: str | Path) -> list[tuple[Path, list[str], list[str]]]:
378
331
  """Walk directory tree."""
379
- pass
332
+ ...
380
333
 
381
334
  @staticmethod
382
- @abstractmethod
383
- def get_size_static(path: Union[str, Path]) -> int:
335
+ def get_size_static(path: str | Path) -> int:
384
336
  """Get directory size."""
385
- pass
337
+ ...
386
338
 
387
339
  @staticmethod
388
- @abstractmethod
389
- def is_empty_static(path: Union[str, Path]) -> bool:
340
+ def is_empty_static(path: str | Path) -> bool:
390
341
  """Check if directory is empty."""
391
- pass
342
+ ...
392
343
 
393
344
  @staticmethod
394
- @abstractmethod
395
- def copy_dir(source: Union[str, Path], destination: Union[str, Path]) -> bool:
345
+ def copy_dir(source: str | Path, destination: str | Path) -> bool:
396
346
  """Copy directory."""
397
- pass
347
+ ...
398
348
 
399
349
  @staticmethod
400
- @abstractmethod
401
- def move_dir(source: Union[str, Path], destination: Union[str, Path]) -> bool:
350
+ def move_dir(source: str | Path, destination: str | Path) -> bool:
402
351
  """Move directory."""
403
- pass
352
+ ...
404
353
 
405
354
  @staticmethod
406
- @abstractmethod
407
- def get_permissions(path: Union[str, Path]) -> int:
355
+ def get_permissions(path: str | Path) -> int:
408
356
  """Get directory permissions."""
409
- pass
357
+ ...
410
358
 
411
359
  @staticmethod
412
- @abstractmethod
413
- def is_readable(path: Union[str, Path]) -> bool:
360
+ def is_readable(path: str | Path) -> bool:
414
361
  """Check if directory is readable."""
415
- pass
362
+ ...
416
363
 
417
364
  @staticmethod
418
- @abstractmethod
419
- def is_writable(path: Union[str, Path]) -> bool:
365
+ def is_writable(path: str | Path) -> bool:
420
366
  """Check if directory is writable."""
421
- pass
367
+ ...
422
368
 
423
369
  @staticmethod
424
- @abstractmethod
425
- def is_executable(path: Union[str, Path]) -> bool:
370
+ def is_executable(path: str | Path) -> bool:
426
371
  """Check if directory is executable."""
427
- pass
372
+ ...
428
373
 
429
374
 
430
375
  # ============================================================================
431
376
  # PATH INTERFACES
432
377
  # ============================================================================
433
378
 
434
- class IPath(ABC):
379
+ @runtime_checkable
380
+ class IPath(Protocol):
435
381
  """
436
382
  Interface for path operations with both static and instance methods.
437
383
 
@@ -446,107 +392,92 @@ class IPath(ABC):
446
392
  # ============================================================================
447
393
 
448
394
  @staticmethod
449
- @abstractmethod
450
- def normalize(path: Union[str, Path]) -> Path:
395
+ def normalize(path: str | Path) -> Path:
451
396
  """Normalize path."""
452
- pass
397
+ ...
453
398
 
454
399
  @staticmethod
455
- @abstractmethod
456
- def resolve(path: Union[str, Path]) -> Path:
400
+ def resolve(path: str | Path) -> Path:
457
401
  """Resolve path."""
458
- pass
402
+ ...
459
403
 
460
404
  @staticmethod
461
- @abstractmethod
462
- def absolute(path: Union[str, Path]) -> Path:
405
+ def absolute(path: str | Path) -> Path:
463
406
  """Get absolute path."""
464
- pass
407
+ ...
465
408
 
466
409
  @staticmethod
467
- @abstractmethod
468
- def relative(path: Union[str, Path], start: Optional[Union[str, Path]] = None) -> Path:
410
+ def relative(path: str | Path, start: Optional[str | Path] = None) -> Path:
469
411
  """Get relative path."""
470
- pass
412
+ ...
471
413
 
472
414
  @staticmethod
473
- @abstractmethod
474
- def join(*paths: Union[str, Path]) -> Path:
415
+ def join(*paths: str | Path) -> Path:
475
416
  """Join paths."""
476
- pass
417
+ ...
477
418
 
478
419
  @staticmethod
479
- @abstractmethod
480
- def split(path: Union[str, Path]) -> tuple[Path, str]:
420
+ def split(path: str | Path) -> tuple[Path, str]:
481
421
  """Split path into directory and filename."""
482
- pass
422
+ ...
483
423
 
484
424
  @staticmethod
485
- @abstractmethod
486
- def get_extension(path: Union[str, Path]) -> str:
425
+ def get_extension(path: str | Path) -> str:
487
426
  """Get file extension."""
488
- pass
427
+ ...
489
428
 
490
429
  @staticmethod
491
- @abstractmethod
492
- def get_stem(path: Union[str, Path]) -> str:
430
+ def get_stem(path: str | Path) -> str:
493
431
  """Get file stem (name without extension)."""
494
- pass
432
+ ...
495
433
 
496
434
  @staticmethod
497
- @abstractmethod
498
- def get_name(path: Union[str, Path]) -> str:
435
+ def get_name(path: str | Path) -> str:
499
436
  """Get file/directory name."""
500
- pass
437
+ ...
501
438
 
502
439
  @staticmethod
503
- @abstractmethod
504
- def get_parent(path: Union[str, Path]) -> Path:
440
+ def get_parent(path: str | Path) -> Path:
505
441
  """Get parent directory."""
506
- pass
442
+ ...
507
443
 
508
444
  @staticmethod
509
- @abstractmethod
510
- def is_absolute(path: Union[str, Path]) -> bool:
445
+ def is_absolute(path: str | Path) -> bool:
511
446
  """Check if path is absolute."""
512
- pass
447
+ ...
513
448
 
514
449
  @staticmethod
515
- @abstractmethod
516
- def is_relative(path: Union[str, Path]) -> bool:
450
+ def is_relative(path: str | Path) -> bool:
517
451
  """Check if path is relative."""
518
- pass
452
+ ...
519
453
 
520
454
  @staticmethod
521
- @abstractmethod
522
- def get_parts(path: Union[str, Path]) -> tuple:
455
+ def get_parts(path: str | Path) -> tuple:
523
456
  """Get path parts."""
524
- pass
457
+ ...
525
458
 
526
459
  @staticmethod
527
- @abstractmethod
528
- def match(path: Union[str, Path], pattern: str) -> bool:
460
+ def match(path: str | Path, pattern: str) -> bool:
529
461
  """Check if path matches pattern."""
530
- pass
462
+ ...
531
463
 
532
464
  @staticmethod
533
- @abstractmethod
534
- def with_suffix(path: Union[str, Path], suffix: str) -> Path:
465
+ def with_suffix(path: str | Path, suffix: str) -> Path:
535
466
  """Get path with new suffix."""
536
- pass
467
+ ...
537
468
 
538
469
  @staticmethod
539
- @abstractmethod
540
- def with_name(path: Union[str, Path], name: str) -> Path:
470
+ def with_name(path: str | Path, name: str) -> Path:
541
471
  """Get path with new name."""
542
- pass
472
+ ...
543
473
 
544
474
 
545
475
  # ============================================================================
546
476
  # STREAM INTERFACES
547
477
  # ============================================================================
548
478
 
549
- class IStream(ABC):
479
+ @runtime_checkable
480
+ class IStream(Protocol):
550
481
  """
551
482
  Interface for stream operations with both static and instance methods.
552
483
 
@@ -560,76 +491,66 @@ class IStream(ABC):
560
491
  # INSTANCE METHODS
561
492
  # ============================================================================
562
493
 
563
- @abstractmethod
564
- def read(self, size: Optional[int] = None) -> Union[str, bytes]:
494
+ def read(self, size: Optional[int] = None) -> str | bytes:
565
495
  """Read from stream."""
566
- pass
496
+ ...
567
497
 
568
- @abstractmethod
569
- def write(self, data: Union[str, bytes]) -> int:
498
+ def write(self, data: str | bytes) -> int:
570
499
  """Write to stream."""
571
- pass
500
+ ...
572
501
 
573
- @abstractmethod
574
502
  def seek(self, position: int, whence: int = 0) -> int:
575
503
  """Seek stream position."""
576
- pass
504
+ ...
577
505
 
578
- @abstractmethod
579
506
  def tell(self) -> int:
580
507
  """Get current stream position."""
581
- pass
508
+ ...
582
509
 
583
- @abstractmethod
584
510
  def flush(self) -> None:
585
511
  """Flush stream buffer."""
586
- pass
512
+ ...
587
513
 
588
- @abstractmethod
589
514
  def close(self) -> None:
590
515
  """Close stream."""
591
- pass
516
+ ...
592
517
 
593
518
  # ============================================================================
594
519
  # STATIC METHODS
595
520
  # ============================================================================
596
521
 
597
522
  @staticmethod
598
- @abstractmethod
599
- def open_file(path: Union[str, Path], mode: str = 'r', encoding: Optional[str] = None) -> Union[TextIO, BinaryIO]:
523
+ def open_file(path: str | Path, mode: str = 'r', encoding: Optional[str] = None) -> TextIO | BinaryIO:
600
524
  """Open file as stream."""
601
- pass
525
+ ...
602
526
 
603
527
  @staticmethod
604
- @abstractmethod
605
- def is_closed(stream: Union[TextIO, BinaryIO]) -> bool:
528
+ def is_closed(stream: TextIO | BinaryIO) -> bool:
606
529
  """Check if stream is closed."""
607
- pass
530
+ ...
608
531
 
609
532
  @staticmethod
610
- @abstractmethod
611
- def readable(stream: Union[TextIO, BinaryIO]) -> bool:
533
+ def readable(stream: TextIO | BinaryIO) -> bool:
612
534
  """Check if stream is readable."""
613
- pass
535
+ ...
614
536
 
615
537
  @staticmethod
616
- @abstractmethod
617
- def writable(stream: Union[TextIO, BinaryIO]) -> bool:
538
+ def writable(stream: TextIO | BinaryIO) -> bool:
618
539
  """Check if stream is writable."""
619
- pass
540
+ ...
620
541
 
621
542
  @staticmethod
622
- @abstractmethod
623
- def seekable(stream: Union[TextIO, BinaryIO]) -> bool:
543
+ def seekable(stream: TextIO | BinaryIO) -> bool:
624
544
  """Check if stream is seekable."""
625
- pass
545
+ ...
626
546
 
627
547
 
628
548
  # ============================================================================
629
549
  # ASYNC I/O INTERFACES
630
550
  # ============================================================================
631
551
 
632
- class IAsyncIO(ABC):
552
+ @runtime_checkable
553
+ class IAsyncIO(Protocol):
633
554
  """
634
555
  Interface for async I/O operations with both static and instance methods.
635
556
 
@@ -643,76 +564,66 @@ class IAsyncIO(ABC):
643
564
  # INSTANCE METHODS
644
565
  # ============================================================================
645
566
 
646
- @abstractmethod
647
- async def aread(self, size: Optional[int] = None) -> Union[str, bytes]:
567
+ async def aread(self, size: Optional[int] = None) -> str | bytes:
648
568
  """Async read operation."""
649
- pass
569
+ ...
650
570
 
651
- @abstractmethod
652
- async def awrite(self, data: Union[str, bytes]) -> int:
571
+ async def awrite(self, data: str | bytes) -> int:
653
572
  """Async write operation."""
654
- pass
573
+ ...
655
574
 
656
- @abstractmethod
657
575
  async def aseek(self, position: int, whence: int = 0) -> int:
658
576
  """Async seek operation."""
659
- pass
577
+ ...
660
578
 
661
- @abstractmethod
662
579
  async def atell(self) -> int:
663
580
  """Async tell operation."""
664
- pass
581
+ ...
665
582
 
666
- @abstractmethod
667
583
  async def aflush(self) -> None:
668
584
  """Async flush operation."""
669
- pass
585
+ ...
670
586
 
671
- @abstractmethod
672
587
  async def aclose(self) -> None:
673
588
  """Async close operation."""
674
- pass
589
+ ...
675
590
 
676
591
  # ============================================================================
677
592
  # STATIC METHODS
678
593
  # ============================================================================
679
594
 
680
595
  @staticmethod
681
- @abstractmethod
682
- async def aopen_file(path: Union[str, Path], mode: str = 'r', encoding: Optional[str] = None) -> Any:
596
+ async def aopen_file(path: str | Path, mode: str = 'r', encoding: Optional[str] = None) -> Any:
683
597
  """Async open file."""
684
- pass
598
+ ...
685
599
 
686
600
  @staticmethod
687
- @abstractmethod
688
- async def aread_text(path: Union[str, Path], encoding: str = 'utf-8') -> str:
601
+ async def aread_text(path: str | Path, encoding: str = 'utf-8') -> str:
689
602
  """Async read text file."""
690
- pass
603
+ ...
691
604
 
692
605
  @staticmethod
693
- @abstractmethod
694
- async def aread_bytes(path: Union[str, Path]) -> bytes:
606
+ async def aread_bytes(path: str | Path) -> bytes:
695
607
  """Async read binary file."""
696
- pass
608
+ ...
697
609
 
698
610
  @staticmethod
699
- @abstractmethod
700
- async def awrite_text(path: Union[str, Path], content: str, encoding: str = 'utf-8') -> bool:
611
+ async def awrite_text(path: str | Path, content: str, encoding: str = 'utf-8') -> bool:
701
612
  """Async write text to file."""
702
- pass
613
+ ...
703
614
 
704
615
  @staticmethod
705
- @abstractmethod
706
- async def awrite_bytes(path: Union[str, Path], content: bytes) -> bool:
616
+ async def awrite_bytes(path: str | Path, content: bytes) -> bool:
707
617
  """Async write bytes to file."""
708
- pass
618
+ ...
709
619
 
710
620
 
711
621
  # ============================================================================
712
622
  # ATOMIC OPERATIONS INTERFACES
713
623
  # ============================================================================
714
624
 
715
- class IAtomicOperations(ABC):
625
+ @runtime_checkable
626
+ class IAtomicOperations(Protocol):
716
627
  """
717
628
  Interface for atomic operations with both static and instance methods.
718
629
 
@@ -726,73 +637,64 @@ class IAtomicOperations(ABC):
726
637
  # INSTANCE METHODS
727
638
  # ============================================================================
728
639
 
729
- @abstractmethod
730
- def atomic_write(self, file_path: Union[str, Path], data: Union[str, bytes],
640
+ def atomic_write(self, file_path: str | Path, data: str | bytes,
731
641
  backup: bool = True) -> OperationResult:
732
642
  """Atomically write data to file."""
733
- pass
643
+ ...
734
644
 
735
- @abstractmethod
736
- def atomic_copy(self, source: Union[str, Path], destination: Union[str, Path]) -> OperationResult:
645
+ def atomic_copy(self, source: str | Path, destination: str | Path) -> OperationResult:
737
646
  """Atomically copy file."""
738
- pass
647
+ ...
739
648
 
740
- @abstractmethod
741
- def atomic_move(self, source: Union[str, Path], destination: Union[str, Path]) -> OperationResult:
649
+ def atomic_move(self, source: str | Path, destination: str | Path) -> OperationResult:
742
650
  """Atomically move file."""
743
- pass
651
+ ...
744
652
 
745
- @abstractmethod
746
- def atomic_delete(self, file_path: Union[str, Path], backup: bool = True) -> OperationResult:
653
+ def atomic_delete(self, file_path: str | Path, backup: bool = True) -> OperationResult:
747
654
  """Atomically delete file."""
748
- pass
655
+ ...
749
656
 
750
- @abstractmethod
751
- def atomic_rename(self, old_path: Union[str, Path], new_path: Union[str, Path]) -> OperationResult:
657
+ def atomic_rename(self, old_path: str | Path, new_path: str | Path) -> OperationResult:
752
658
  """Atomically rename file."""
753
- pass
659
+ ...
754
660
 
755
661
  # ============================================================================
756
662
  # STATIC METHODS
757
663
  # ============================================================================
758
664
 
759
665
  @staticmethod
760
- @abstractmethod
761
- def atomic_write_static(file_path: Union[str, Path], data: Union[str, bytes],
666
+ def atomic_write_static(file_path: str | Path, data: str | bytes,
762
667
  backup: bool = True) -> OperationResult:
763
668
  """Atomically write data to file."""
764
- pass
669
+ ...
765
670
 
766
671
  @staticmethod
767
- @abstractmethod
768
- def atomic_copy_static(source: Union[str, Path], destination: Union[str, Path]) -> OperationResult:
672
+ def atomic_copy_static(source: str | Path, destination: str | Path) -> OperationResult:
769
673
  """Atomically copy file."""
770
- pass
674
+ ...
771
675
 
772
676
  @staticmethod
773
- @abstractmethod
774
- def atomic_move_static(source: Union[str, Path], destination: Union[str, Path]) -> OperationResult:
677
+ def atomic_move_static(source: str | Path, destination: str | Path) -> OperationResult:
775
678
  """Atomically move file."""
776
- pass
679
+ ...
777
680
 
778
681
  @staticmethod
779
- @abstractmethod
780
- def atomic_delete_static(file_path: Union[str, Path], backup: bool = True) -> OperationResult:
682
+ def atomic_delete_static(file_path: str | Path, backup: bool = True) -> OperationResult:
781
683
  """Atomically delete file."""
782
- pass
684
+ ...
783
685
 
784
686
  @staticmethod
785
- @abstractmethod
786
- def atomic_rename_static(old_path: Union[str, Path], new_path: Union[str, Path]) -> OperationResult:
687
+ def atomic_rename_static(old_path: str | Path, new_path: str | Path) -> OperationResult:
787
688
  """Atomically rename file."""
788
- pass
689
+ ...
789
690
 
790
691
 
791
692
  # ============================================================================
792
693
  # BACKUP OPERATIONS INTERFACES
793
694
  # ============================================================================
794
695
 
795
- class IBackupOperations(ABC):
696
+ @runtime_checkable
697
+ class IBackupOperations(Protocol):
796
698
  """
797
699
  Interface for backup operations with both static and instance methods.
798
700
 
@@ -806,71 +708,62 @@ class IBackupOperations(ABC):
806
708
  # INSTANCE METHODS
807
709
  # ============================================================================
808
710
 
809
- @abstractmethod
810
- def create_backup(self, source: Union[str, Path], backup_dir: Union[str, Path]) -> Optional[Path]:
711
+ def create_backup(self, source: str | Path, backup_dir: str | Path) -> Optional[Path]:
811
712
  """Create backup of file or directory."""
812
- pass
713
+ ...
813
714
 
814
- @abstractmethod
815
- def restore_backup(self, backup_path: Union[str, Path], target: Union[str, Path]) -> OperationResult:
715
+ def restore_backup(self, backup_path: str | Path, target: str | Path) -> OperationResult:
816
716
  """Restore from backup."""
817
- pass
717
+ ...
818
718
 
819
- @abstractmethod
820
- def list_backups(self, backup_dir: Union[str, Path]) -> list[Path]:
719
+ def list_backups(self, backup_dir: str | Path) -> list[Path]:
821
720
  """List available backups."""
822
- pass
721
+ ...
823
722
 
824
- @abstractmethod
825
- def cleanup_backups(self, backup_dir: Union[str, Path], max_age_days: int = 30) -> int:
723
+ def cleanup_backups(self, backup_dir: str | Path, max_age_days: int = 30) -> int:
826
724
  """Cleanup old backups."""
827
- pass
725
+ ...
828
726
 
829
- @abstractmethod
830
- def verify_backup(self, backup_path: Union[str, Path]) -> bool:
727
+ def verify_backup(self, backup_path: str | Path) -> bool:
831
728
  """Verify backup integrity."""
832
- pass
729
+ ...
833
730
 
834
731
  # ============================================================================
835
732
  # STATIC METHODS
836
733
  # ============================================================================
837
734
 
838
735
  @staticmethod
839
- @abstractmethod
840
- def create_backup_static(source: Union[str, Path], backup_dir: Union[str, Path]) -> Optional[Path]:
736
+ def create_backup_static(source: str | Path, backup_dir: str | Path) -> Optional[Path]:
841
737
  """Create backup of file or directory."""
842
- pass
738
+ ...
843
739
 
844
740
  @staticmethod
845
- @abstractmethod
846
- def restore_backup_static(backup_path: Union[str, Path], target: Union[str, Path]) -> OperationResult:
741
+ def restore_backup_static(backup_path: str | Path, target: str | Path) -> OperationResult:
847
742
  """Restore from backup."""
848
- pass
743
+ ...
849
744
 
850
745
  @staticmethod
851
- @abstractmethod
852
- def list_backups_static(backup_dir: Union[str, Path]) -> list[Path]:
746
+ def list_backups_static(backup_dir: str | Path) -> list[Path]:
853
747
  """List available backups."""
854
- pass
748
+ ...
855
749
 
856
750
  @staticmethod
857
- @abstractmethod
858
- def cleanup_backups_static(backup_dir: Union[str, Path], max_age_days: int = 30) -> int:
751
+ def cleanup_backups_static(backup_dir: str | Path, max_age_days: int = 30) -> int:
859
752
  """Cleanup old backups."""
860
- pass
753
+ ...
861
754
 
862
755
  @staticmethod
863
- @abstractmethod
864
- def verify_backup_static(backup_path: Union[str, Path]) -> bool:
756
+ def verify_backup_static(backup_path: str | Path) -> bool:
865
757
  """Verify backup integrity."""
866
- pass
758
+ ...
867
759
 
868
760
 
869
761
  # ============================================================================
870
762
  # TEMPORARY OPERATIONS INTERFACES
871
763
  # ============================================================================
872
764
 
873
- class ITemporaryOperations(ABC):
765
+ @runtime_checkable
766
+ class ITemporaryOperations(Protocol):
874
767
  """
875
768
  Interface for temporary operations with both static and instance methods.
876
769
 
@@ -884,59 +777,50 @@ class ITemporaryOperations(ABC):
884
777
  # INSTANCE METHODS
885
778
  # ============================================================================
886
779
 
887
- @abstractmethod
888
780
  def create_temp_file(self, suffix: Optional[str] = None, prefix: Optional[str] = None) -> Path:
889
781
  """Create temporary file."""
890
- pass
782
+ ...
891
783
 
892
- @abstractmethod
893
784
  def create_temp_directory(self, suffix: Optional[str] = None, prefix: Optional[str] = None) -> Path:
894
785
  """Create temporary directory."""
895
- pass
786
+ ...
896
787
 
897
- @abstractmethod
898
- def cleanup_temp(self, path: Union[str, Path]) -> bool:
788
+ def cleanup_temp(self, path: str | Path) -> bool:
899
789
  """Cleanup temporary file or directory."""
900
- pass
790
+ ...
901
791
 
902
- @abstractmethod
903
792
  def cleanup_all_temp(self) -> int:
904
793
  """Cleanup all temporary files and directories."""
905
- pass
794
+ ...
906
795
 
907
796
  # ============================================================================
908
797
  # STATIC METHODS
909
798
  # ============================================================================
910
799
 
911
800
  @staticmethod
912
- @abstractmethod
913
801
  def create_temp_file_static(suffix: Optional[str] = None, prefix: Optional[str] = None) -> Path:
914
802
  """Create temporary file."""
915
- pass
803
+ ...
916
804
 
917
805
  @staticmethod
918
- @abstractmethod
919
806
  def create_temp_directory_static(suffix: Optional[str] = None, prefix: Optional[str] = None) -> Path:
920
807
  """Create temporary directory."""
921
- pass
808
+ ...
922
809
 
923
810
  @staticmethod
924
- @abstractmethod
925
- def cleanup_temp_static(path: Union[str, Path]) -> bool:
811
+ def cleanup_temp_static(path: str | Path) -> bool:
926
812
  """Cleanup temporary file or directory."""
927
- pass
813
+ ...
928
814
 
929
815
  @staticmethod
930
- @abstractmethod
931
816
  def get_temp_base_dir() -> Path:
932
817
  """Get temporary base directory."""
933
- pass
818
+ ...
934
819
 
935
820
  @staticmethod
936
- @abstractmethod
937
- def is_temp(path: Union[str, Path]) -> bool:
821
+ def is_temp(path: str | Path) -> bool:
938
822
  """Check if path is temporary."""
939
- pass
823
+ ...
940
824
 
941
825
 
942
826
  # ============================================================================
@@ -963,7 +847,7 @@ class IUnifiedIO(IFile, IFolder, IPath, IStream, IAsyncIO, IAtomicOperations, IB
963
847
 
964
848
  This interface follows the xwsystem pattern of combining existing interfaces
965
849
  rather than creating new abstractions, maximizing code reuse and maintaining
966
- backward compatibility.
850
+ code reuse.
967
851
  """
968
852
  pass
969
853
 
@@ -1001,110 +885,103 @@ class IFileManager(IFile, IFolder, IPath, IAtomicOperations, IBackupOperations,
1001
885
  # DATA SOURCE INTERFACES (Used by file/, stream/)
1002
886
  # ============================================================================
1003
887
 
1004
- class IDataSource[T](ABC):
888
+ @runtime_checkable
889
+ class IDataSource[T](Protocol):
1005
890
  """Universal data source interface for various data sources."""
1006
891
 
1007
- @abstractmethod
1008
892
  def read(self) -> T:
1009
893
  """Read data from source."""
1010
- pass
894
+ ...
1011
895
 
1012
- @abstractmethod
1013
896
  def write(self, data: T) -> None:
1014
897
  """Write data to source."""
1015
- pass
898
+ ...
1016
899
 
1017
900
 
1018
- class IPagedDataSource[T](ABC):
901
+ @runtime_checkable
902
+ class IPagedDataSource[T](Protocol):
1019
903
  """Paged data source interface for large data sets."""
1020
904
 
1021
- @abstractmethod
1022
905
  def read_page(self, page_number: int) -> list[T]:
1023
906
  """Read a specific page of data."""
1024
- pass
907
+ ...
1025
908
 
1026
- @abstractmethod
1027
909
  def get_page_count(self) -> int:
1028
910
  """Get total number of pages."""
1029
- pass
911
+ ...
1030
912
 
1031
913
 
1032
914
  # ============================================================================
1033
915
  # CODEC-INTEGRATED IO INTERFACES (Used by stream/)
1034
916
  # ============================================================================
1035
917
 
1036
- class ICodecIO[T, R](ABC):
918
+ @runtime_checkable
919
+ class ICodecIO[T, R](Protocol):
1037
920
  """Codec-integrated IO interface with source type T and result type R."""
1038
921
 
1039
- @abstractmethod
1040
922
  def read_as(self, codec: str):
1041
923
  """Read and decode data using specified codec."""
1042
- pass
924
+ ...
1043
925
 
1044
- @abstractmethod
1045
926
  def write_as(self, data, codec: str) -> None:
1046
927
  """Encode and write data using specified codec."""
1047
- pass
928
+ ...
1048
929
 
1049
930
 
1050
- class IPagedCodecIO[T, R](ABC):
931
+ @runtime_checkable
932
+ class IPagedCodecIO[T, R](Protocol):
1051
933
  """Paged codec-integrated IO interface with source type T and result type R."""
1052
934
 
1053
- @abstractmethod
1054
935
  def read_page_as(self, page_number: int, codec: str):
1055
936
  """Read and decode a page using specified codec."""
1056
- pass
937
+ ...
1057
938
 
1058
939
 
1059
940
  # ============================================================================
1060
941
  # FILE SYSTEM INTERFACES (Used by common/, filesystem/)
1061
942
  # ============================================================================
1062
943
 
1063
- class IFileWatcher(ABC):
944
+ @runtime_checkable
945
+ class IFileWatcher(Protocol):
1064
946
  """Interface for watching file system changes."""
1065
947
 
1066
- @abstractmethod
1067
- def watch(self, path: Union[str, Path]) -> None:
948
+ def watch(self, path: str | Path) -> None:
1068
949
  """Start watching a path."""
1069
- pass
950
+ ...
1070
951
 
1071
- @abstractmethod
1072
952
  def stop(self) -> None:
1073
953
  """Stop watching."""
1074
- pass
954
+ ...
1075
955
 
1076
956
 
1077
- class IFileLock(ABC):
957
+ @runtime_checkable
958
+ class IFileLock(Protocol):
1078
959
  """Interface for file locking."""
1079
960
 
1080
- @abstractmethod
1081
961
  def acquire(self) -> bool:
1082
962
  """Acquire the lock."""
1083
- pass
963
+ ...
1084
964
 
1085
- @abstractmethod
1086
965
  def release(self) -> None:
1087
966
  """Release the lock."""
1088
- pass
967
+ ...
1089
968
 
1090
969
 
1091
- class IFileSystem(ABC):
970
+ @runtime_checkable
971
+ class IFileSystem(Protocol):
1092
972
  """Virtual file system interface."""
1093
973
 
1094
- @abstractmethod
1095
974
  def read(self, path: str) -> bytes:
1096
975
  """Read file contents."""
1097
- pass
976
+ ...
1098
977
 
1099
- @abstractmethod
1100
978
  def write(self, path: str, data: bytes) -> None:
1101
979
  """Write file contents."""
1102
- pass
980
+ ...
1103
981
 
1104
- @abstractmethod
1105
982
  def exists(self, path: str) -> bool:
1106
983
  """Check if path exists."""
1107
- pass
984
+ ...
1108
985
 
1109
986
 
1110
987
  # ============================================================================
@@ -1393,7 +1270,7 @@ class IAtomicWriter(Protocol):
1393
1270
  """Write data atomically."""
1394
1271
  ...
1395
1272
 
1396
- def __enter__(self) -> 'IAtomicWriter':
1273
+ def __enter__(self) -> IAtomicWriter:
1397
1274
  """Enter context manager."""
1398
1275
  ...
1399
1276
 
@@ -1423,23 +1300,21 @@ class IArchiver[T](ICodec[T, bytes]):
1423
1300
  NOT limited to file paths - works on data in RAM!
1424
1301
  """
1425
1302
 
1426
- @abstractmethod
1427
1303
  def compress(self, data: T, **options) -> bytes:
1428
1304
  """
1429
1305
  Compress data to archive bytes (in RAM).
1430
1306
 
1431
1307
  Delegates to encode() internally.
1432
1308
  """
1433
- pass
1309
+ ...
1434
1310
 
1435
- @abstractmethod
1436
1311
  def extract(self, archive_bytes: bytes, **options) -> T:
1437
1312
  """
1438
1313
  Extract archive bytes to data (in RAM).
1439
1314
 
1440
1315
  Delegates to decode() internally.
1441
1316
  """
1442
- pass
1317
+ ...
1443
1318
 
1444
1319
 
1445
1320
  class IArchiveFile(IFile):
@@ -1455,28 +1330,25 @@ class IArchiveFile(IFile):
1455
1330
  - Archive file management
1456
1331
  """
1457
1332
 
1458
- @abstractmethod
1459
1333
  def add_files(self, files: list[Path], **options) -> None:
1460
1334
  """Add files to archive (uses archiver.compress internally)."""
1461
- pass
1335
+ ...
1462
1336
 
1463
- @abstractmethod
1464
1337
  def extract_to(self, dest: Path, **options) -> list[Path]:
1465
1338
  """Extract archive to destination (uses archiver.extract internally)."""
1466
- pass
1339
+ ...
1467
1340
 
1468
- @abstractmethod
1469
1341
  def list_contents(self) -> list[str]:
1470
1342
  """List files in archive."""
1471
- pass
1343
+ ...
1472
1344
 
1473
- @abstractmethod
1474
1345
  def get_archiver(self) -> IArchiver:
1475
1346
  """Get the underlying archiver codec."""
1476
- pass
1347
+ ...
1477
1348
 
1478
1349
 
1479
- class ICompression(ABC):
1350
+ @runtime_checkable
1351
+ class ICompression(Protocol):
1480
1352
  """
1481
1353
  Interface for raw compression operations (gzip, bz2, lzma, etc.).
1482
1354
 
@@ -1484,30 +1356,28 @@ class ICompression(ABC):
1484
1356
  Separate from IArchiver which handles archive formats.
1485
1357
  """
1486
1358
 
1487
- @abstractmethod
1488
1359
  def compress(self, data: bytes, **options) -> bytes:
1489
1360
  """Compress raw bytes."""
1490
- pass
1361
+ ...
1491
1362
 
1492
- @abstractmethod
1493
1363
  def decompress(self, data: bytes, **options) -> bytes:
1494
1364
  """Decompress raw bytes."""
1495
- pass
1365
+ ...
1496
1366
 
1497
1367
 
1498
1368
  @runtime_checkable
1499
1369
  class IPathValidator(Protocol):
1500
1370
  """Interface for path validation and security checks."""
1501
1371
 
1502
- def validate_path(self, path: Union[str, Path]) -> bool:
1372
+ def validate_path(self, path: str | Path) -> bool:
1503
1373
  """Validate path safety."""
1504
1374
  ...
1505
1375
 
1506
- def is_safe_path(self, path: Union[str, Path]) -> bool:
1376
+ def is_safe_path(self, path: str | Path) -> bool:
1507
1377
  """Check if path is safe to use."""
1508
1378
  ...
1509
1379
 
1510
- def normalize_path(self, path: Union[str, Path]) -> Path:
1380
+ def normalize_path(self, path: str | Path) -> Path:
1511
1381
  """Normalize and resolve path."""
1512
1382
  ...
1513
1383
 
@@ -1529,11 +1399,11 @@ class IFileSource(Protocol):
1529
1399
  """URI scheme."""
1530
1400
  ...
1531
1401
 
1532
- def read(self, **options) -> Union[bytes, str]:
1402
+ def read(self, **options) -> bytes | str:
1533
1403
  """Read entire file content."""
1534
1404
  ...
1535
1405
 
1536
- def write(self, data: Union[bytes, str], **options) -> None:
1406
+ def write(self, data: bytes | str, **options) -> None:
1537
1407
  """Write entire content to file."""
1538
1408
  ...
1539
1409
 
@@ -1554,19 +1424,19 @@ class IPagedSource(Protocol):
1554
1424
  """Total file size in bytes."""
1555
1425
  ...
1556
1426
 
1557
- def read_page(self, page: int, page_size: int, **options) -> Union[bytes, str]:
1427
+ def read_page(self, page: int, page_size: int, **options) -> bytes | str:
1558
1428
  """Read specific page."""
1559
1429
  ...
1560
1430
 
1561
- def read_chunk(self, offset: int, size: int, **options) -> Union[bytes, str]:
1431
+ def read_chunk(self, offset: int, size: int, **options) -> bytes | str:
1562
1432
  """Read chunk by byte offset."""
1563
1433
  ...
1564
1434
 
1565
- def iter_pages(self, page_size: int, **options) -> Iterator[Union[bytes, str]]:
1435
+ def iter_pages(self, page_size: int, **options) -> Iterator[bytes | str]:
1566
1436
  """Iterate over pages."""
1567
1437
  ...
1568
1438
 
1569
- def iter_chunks(self, chunk_size: int, **options) -> Iterator[Union[bytes, str]]:
1439
+ def iter_chunks(self, chunk_size: int, **options) -> Iterator[bytes | str]:
1570
1440
  """Iterate over chunks."""
1571
1441
  ...
1572
1442
 
@@ -1595,7 +1465,7 @@ class IPagingStrategy(Protocol):
1595
1465
  mode: str = 'rb',
1596
1466
  encoding: Optional[str] = None,
1597
1467
  **options
1598
- ) -> Union[bytes, str]:
1468
+ ) -> bytes | str:
1599
1469
  """
1600
1470
  Read specific page using this strategy.
1601
1471
 
@@ -1619,7 +1489,7 @@ class IPagingStrategy(Protocol):
1619
1489
  mode: str = 'rb',
1620
1490
  encoding: Optional[str] = None,
1621
1491
  **options
1622
- ) -> Iterator[Union[bytes, str]]:
1492
+ ) -> Iterator[bytes | str]:
1623
1493
  """
1624
1494
  Iterate over pages using this strategy.
1625
1495
 
@@ -1698,12 +1568,10 @@ class IPagedCodecIO[T, R](ICodecIO[T, R]):
1698
1568
  Interface for paged codec I/O.
1699
1569
  """
1700
1570
 
1701
- @abstractmethod
1702
1571
  def iter_items(self, page_size: int, **opts):
1703
1572
  """Iterate over decoded items."""
1704
1573
  ...
1705
1574
 
1706
- @abstractmethod
1707
1575
  def load_page(self, page: int, page_size: int, **opts) -> list[T]:
1708
1576
  """Load specific page."""
1709
1577
  ...