pysage-tools 0.1.0__tar.gz

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 (291) hide show
  1. pysage_tools-0.1.0/LICENSE +21 -0
  2. pysage_tools-0.1.0/PKG-INFO +127 -0
  3. pysage_tools-0.1.0/README.md +87 -0
  4. pysage_tools-0.1.0/pyproject.toml +184 -0
  5. pysage_tools-0.1.0/pysage_tools.egg-info/PKG-INFO +127 -0
  6. pysage_tools-0.1.0/pysage_tools.egg-info/SOURCES.txt +289 -0
  7. pysage_tools-0.1.0/pysage_tools.egg-info/dependency_links.txt +1 -0
  8. pysage_tools-0.1.0/pysage_tools.egg-info/entry_points.txt +14 -0
  9. pysage_tools-0.1.0/pysage_tools.egg-info/requires.txt +24 -0
  10. pysage_tools-0.1.0/pysage_tools.egg-info/top_level.txt +10 -0
  11. pysage_tools-0.1.0/sage_apt/__init__.py +19 -0
  12. pysage_tools-0.1.0/sage_apt/__main__.py +164 -0
  13. pysage_tools-0.1.0/sage_apt/actions.py +852 -0
  14. pysage_tools-0.1.0/sage_apt/aptfile.py +1907 -0
  15. pysage_tools-0.1.0/sage_apt/assets/editor.html +1329 -0
  16. pysage_tools-0.1.0/sage_apt/check.py +99 -0
  17. pysage_tools-0.1.0/sage_apt/editor.py +149 -0
  18. pysage_tools-0.1.0/sage_apt/flags.py +173 -0
  19. pysage_tools-0.1.0/sage_apt/geometry.py +107 -0
  20. pysage_tools-0.1.0/sage_apt/imagemap.py +69 -0
  21. pysage_tools-0.1.0/sage_apt/py.typed +0 -0
  22. pysage_tools-0.1.0/sage_apt/textures.py +187 -0
  23. pysage_tools-0.1.0/sage_apt/viewer.py +556 -0
  24. pysage_tools-0.1.0/sage_ini/__init__.py +64 -0
  25. pysage_tools-0.1.0/sage_ini/__main__.py +610 -0
  26. pysage_tools-0.1.0/sage_ini/brief.py +231 -0
  27. pysage_tools-0.1.0/sage_ini/diff.py +384 -0
  28. pysage_tools-0.1.0/sage_ini/loader.py +164 -0
  29. pysage_tools-0.1.0/sage_ini/macro_merge.py +298 -0
  30. pysage_tools-0.1.0/sage_ini/manifest.py +447 -0
  31. pysage_tools-0.1.0/sage_ini/merge.py +491 -0
  32. pysage_tools-0.1.0/sage_ini/model/__init__.py +38 -0
  33. pysage_tools-0.1.0/sage_ini/model/behaviors.py +3740 -0
  34. pysage_tools-0.1.0/sage_ini/model/data_blocks.py +2688 -0
  35. pysage_tools-0.1.0/sage_ini/model/definitions.py +16 -0
  36. pysage_tools-0.1.0/sage_ini/model/draw.py +430 -0
  37. pysage_tools-0.1.0/sage_ini/model/enums.py +2196 -0
  38. pysage_tools-0.1.0/sage_ini/model/fxlist.py +168 -0
  39. pysage_tools-0.1.0/sage_ini/model/game.py +328 -0
  40. pysage_tools-0.1.0/sage_ini/model/ini_objects.py +1397 -0
  41. pysage_tools-0.1.0/sage_ini/model/livingworld.py +351 -0
  42. pysage_tools-0.1.0/sage_ini/model/misc_blocks.py +480 -0
  43. pysage_tools-0.1.0/sage_ini/model/nuggets.py +244 -0
  44. pysage_tools-0.1.0/sage_ini/model/objects.py +621 -0
  45. pysage_tools-0.1.0/sage_ini/model/particles.py +183 -0
  46. pysage_tools-0.1.0/sage_ini/model/state.py +902 -0
  47. pysage_tools-0.1.0/sage_ini/model/types.py +1432 -0
  48. pysage_tools-0.1.0/sage_ini/model/ui.py +55 -0
  49. pysage_tools-0.1.0/sage_ini/model/xref.py +190 -0
  50. pysage_tools-0.1.0/sage_ini/modindex.py +114 -0
  51. pysage_tools-0.1.0/sage_ini/parser/__init__.py +47 -0
  52. pysage_tools-0.1.0/sage_ini/parser/ast.py +109 -0
  53. pysage_tools-0.1.0/sage_ini/parser/blockparser.py +347 -0
  54. pysage_tools-0.1.0/sage_ini/parser/diagnostics.py +73 -0
  55. pysage_tools-0.1.0/sage_ini/parser/io.py +90 -0
  56. pysage_tools-0.1.0/sage_ini/parser/keywords.py +118 -0
  57. pysage_tools-0.1.0/sage_ini/parser/lexer.py +97 -0
  58. pysage_tools-0.1.0/sage_ini/parser/location.py +32 -0
  59. pysage_tools-0.1.0/sage_ini/parser/printer.py +206 -0
  60. pysage_tools-0.1.0/sage_ini/player_diff.py +556 -0
  61. pysage_tools-0.1.0/sage_ini/primer.py +291 -0
  62. pysage_tools-0.1.0/sage_ini/py.typed +0 -0
  63. pysage_tools-0.1.0/sage_ini/skill_assets/bfme-ini/SKILL.md +94 -0
  64. pysage_tools-0.1.0/sage_ini/skill_install.py +18 -0
  65. pysage_tools-0.1.0/sage_ini/stats.py +221 -0
  66. pysage_tools-0.1.0/sage_ini/strings.py +149 -0
  67. pysage_tools-0.1.0/sage_ini/subsystems.py +257 -0
  68. pysage_tools-0.1.0/sage_ini/suggest.py +96 -0
  69. pysage_tools-0.1.0/sage_ini/walk.py +52 -0
  70. pysage_tools-0.1.0/sage_lint/__init__.py +3 -0
  71. pysage_tools-0.1.0/sage_lint/__main__.py +4 -0
  72. pysage_tools-0.1.0/sage_lint/analysis.py +115 -0
  73. pysage_tools-0.1.0/sage_lint/baseline.py +118 -0
  74. pysage_tools-0.1.0/sage_lint/cli.py +566 -0
  75. pysage_tools-0.1.0/sage_lint/commands/__init__.py +3 -0
  76. pysage_tools-0.1.0/sage_lint/commands/common.py +167 -0
  77. pysage_tools-0.1.0/sage_lint/commands/diff.py +112 -0
  78. pysage_tools-0.1.0/sage_lint/commands/duplicates.py +116 -0
  79. pysage_tools-0.1.0/sage_lint/commands/format.py +192 -0
  80. pysage_tools-0.1.0/sage_lint/commands/init.py +44 -0
  81. pysage_tools-0.1.0/sage_lint/commands/lint.py +552 -0
  82. pysage_tools-0.1.0/sage_lint/commands/manifest.py +44 -0
  83. pysage_tools-0.1.0/sage_lint/commands/serve.py +423 -0
  84. pysage_tools-0.1.0/sage_lint/config.py +260 -0
  85. pysage_tools-0.1.0/sage_lint/duplicates.py +292 -0
  86. pysage_tools-0.1.0/sage_lint/fixer.py +272 -0
  87. pysage_tools-0.1.0/sage_lint/formatter.py +153 -0
  88. pysage_tools-0.1.0/sage_lint/linter.py +390 -0
  89. pysage_tools-0.1.0/sage_lint/plugins/sublime/generate_syntax.py +132 -0
  90. pysage_tools-0.1.0/sage_lint/plugins/sublime/sage_lint.py +1985 -0
  91. pysage_tools-0.1.0/sage_lint/plugins/ui/__init__.py +4 -0
  92. pysage_tools-0.1.0/sage_lint/plugins/ui/__main__.py +5 -0
  93. pysage_tools-0.1.0/sage_lint/plugins/ui/app.py +24 -0
  94. pysage_tools-0.1.0/sage_lint/plugins/ui/icon.ico +0 -0
  95. pysage_tools-0.1.0/sage_lint/plugins/ui/runner.py +188 -0
  96. pysage_tools-0.1.0/sage_lint/plugins/ui/window.py +474 -0
  97. pysage_tools-0.1.0/sage_lint/ruleconfig.py +59 -0
  98. pysage_tools-0.1.0/sage_lint/rules/__init__.py +61 -0
  99. pysage_tools-0.1.0/sage_lint/rules/assets.py +203 -0
  100. pysage_tools-0.1.0/sage_lint/rules/base.py +55 -0
  101. pysage_tools-0.1.0/sage_lint/rules/commandset.py +114 -0
  102. pysage_tools-0.1.0/sage_lint/rules/definitions.py +150 -0
  103. pysage_tools-0.1.0/sage_lint/rules/macros.py +94 -0
  104. pysage_tools-0.1.0/sage_lint/rules/map_ini.py +51 -0
  105. pysage_tools-0.1.0/sage_lint/rules/modifier_fx.py +114 -0
  106. pysage_tools-0.1.0/sage_lint/rules/module_ops.py +204 -0
  107. pysage_tools-0.1.0/sage_lint/rules/module_refs.py +72 -0
  108. pysage_tools-0.1.0/sage_lint/rules/modules.py +55 -0
  109. pysage_tools-0.1.0/sage_lint/rules/references.py +185 -0
  110. pysage_tools-0.1.0/sage_lint/rules/respawn.py +85 -0
  111. pysage_tools-0.1.0/sage_lint/rules/schema.py +151 -0
  112. pysage_tools-0.1.0/sage_lint/rules/strings.py +152 -0
  113. pysage_tools-0.1.0/sage_lint/suppressions.py +86 -0
  114. pysage_tools-0.1.0/sage_map/__init__.py +93 -0
  115. pysage_tools-0.1.0/sage_map/__main__.py +107 -0
  116. pysage_tools-0.1.0/sage_map/assets/__init__.py +72 -0
  117. pysage_tools-0.1.0/sage_map/assets/asset_list.py +58 -0
  118. pysage_tools-0.1.0/sage_map/assets/blend_tile_data.py +441 -0
  119. pysage_tools-0.1.0/sage_map/assets/camera_animation_list.py +234 -0
  120. pysage_tools-0.1.0/sage_map/assets/castle_templates.py +171 -0
  121. pysage_tools-0.1.0/sage_map/assets/environment_data.py +77 -0
  122. pysage_tools-0.1.0/sage_map/assets/fog_settings.py +31 -0
  123. pysage_tools-0.1.0/sage_map/assets/global_lighting.py +233 -0
  124. pysage_tools-0.1.0/sage_map/assets/global_version.py +30 -0
  125. pysage_tools-0.1.0/sage_map/assets/height_map.py +118 -0
  126. pysage_tools-0.1.0/sage_map/assets/library_map_lists.py +73 -0
  127. pysage_tools-0.1.0/sage_map/assets/mission_hotspots.py +60 -0
  128. pysage_tools-0.1.0/sage_map/assets/mission_objectives.py +78 -0
  129. pysage_tools-0.1.0/sage_map/assets/mp_positions.py +95 -0
  130. pysage_tools-0.1.0/sage_map/assets/named_cameras.py +85 -0
  131. pysage_tools-0.1.0/sage_map/assets/object_list.py +83 -0
  132. pysage_tools-0.1.0/sage_map/assets/player_scripts.py +570 -0
  133. pysage_tools-0.1.0/sage_map/assets/polygon_triggers.py +200 -0
  134. pysage_tools-0.1.0/sage_map/assets/post_effects_chunk.py +154 -0
  135. pysage_tools-0.1.0/sage_map/assets/river_areas.py +143 -0
  136. pysage_tools-0.1.0/sage_map/assets/sides_list.py +254 -0
  137. pysage_tools-0.1.0/sage_map/assets/skipped_asset.py +31 -0
  138. pysage_tools-0.1.0/sage_map/assets/skybox_settings.py +43 -0
  139. pysage_tools-0.1.0/sage_map/assets/standing_water_area.py +105 -0
  140. pysage_tools-0.1.0/sage_map/assets/standing_waves_area.py +177 -0
  141. pysage_tools-0.1.0/sage_map/assets/teams.py +53 -0
  142. pysage_tools-0.1.0/sage_map/assets/trigger_areas.py +82 -0
  143. pysage_tools-0.1.0/sage_map/assets/water_settings.py +36 -0
  144. pysage_tools-0.1.0/sage_map/assets/waypoint_list.py +40 -0
  145. pysage_tools-0.1.0/sage_map/assets/world_info.py +32 -0
  146. pysage_tools-0.1.0/sage_map/checks/__init__.py +20 -0
  147. pysage_tools-0.1.0/sage_map/checks/height_utils.py +200 -0
  148. pysage_tools-0.1.0/sage_map/checks/linter.py +54 -0
  149. pysage_tools-0.1.0/sage_map/context.py +238 -0
  150. pysage_tools-0.1.0/sage_map/diff.py +810 -0
  151. pysage_tools-0.1.0/sage_map/linter.py +264 -0
  152. pysage_tools-0.1.0/sage_map/map.py +416 -0
  153. pysage_tools-0.1.0/sage_map/model.py +219 -0
  154. pysage_tools-0.1.0/sage_map/properties.py +39 -0
  155. pysage_tools-0.1.0/sage_map/py.typed +0 -0
  156. pysage_tools-0.1.0/sage_map/scripts.py +172 -0
  157. pysage_tools-0.1.0/sage_mods/__init__.py +7 -0
  158. pysage_tools-0.1.0/sage_mods/edain/__init__.py +59 -0
  159. pysage_tools-0.1.0/sage_mods/edain/__main__.py +391 -0
  160. pysage_tools-0.1.0/sage_mods/edain/diff.py +271 -0
  161. pysage_tools-0.1.0/sage_mods/edain/graph.py +70 -0
  162. pysage_tools-0.1.0/sage_mods/edain/icons/Angmar_frontpage.webp +0 -0
  163. pysage_tools-0.1.0/sage_mods/edain/icons/Arnor_frontpage.webp +0 -0
  164. pysage_tools-0.1.0/sage_mods/edain/icons/Belfalas_frontpage.webp +0 -0
  165. pysage_tools-0.1.0/sage_mods/edain/icons/Erebor_frontpage.webp +0 -0
  166. pysage_tools-0.1.0/sage_mods/edain/icons/Ered-Luin_frontpage.webp +0 -0
  167. pysage_tools-0.1.0/sage_mods/edain/icons/Gondor_frontpage.webp +0 -0
  168. pysage_tools-0.1.0/sage_mods/edain/icons/Imladris_frontpage.webp +0 -0
  169. pysage_tools-0.1.0/sage_mods/edain/icons/Iron_Hills_frontpage.webp +0 -0
  170. pysage_tools-0.1.0/sage_mods/edain/icons/Isengard_frontpage.webp +0 -0
  171. pysage_tools-0.1.0/sage_mods/edain/icons/Lothlorien_frontpage.webp +0 -0
  172. pysage_tools-0.1.0/sage_mods/edain/icons/Misty_Mountains_frontpage.webp +0 -0
  173. pysage_tools-0.1.0/sage_mods/edain/icons/Mordor_frontpage.webp +0 -0
  174. pysage_tools-0.1.0/sage_mods/edain/icons/Rohan_frontpage.webp +0 -0
  175. pysage_tools-0.1.0/sage_mods/edain/map_checks/__init__.py +67 -0
  176. pysage_tools-0.1.0/sage_mods/edain/map_checks/findings.py +122 -0
  177. pysage_tools-0.1.0/sage_mods/edain/map_checks/linter.py +353 -0
  178. pysage_tools-0.1.0/sage_mods/edain/map_checks/ui/__init__.py +5 -0
  179. pysage_tools-0.1.0/sage_mods/edain/map_checks/ui/__main__.py +5 -0
  180. pysage_tools-0.1.0/sage_mods/edain/map_checks/ui/app.py +29 -0
  181. pysage_tools-0.1.0/sage_mods/edain/map_checks/ui/icon.ico +0 -0
  182. pysage_tools-0.1.0/sage_mods/edain/map_checks/ui/runner.py +115 -0
  183. pysage_tools-0.1.0/sage_mods/edain/map_checks/ui/window.py +645 -0
  184. pysage_tools-0.1.0/sage_mods/edain/replay.py +463 -0
  185. pysage_tools-0.1.0/sage_mods/edain/report.py +315 -0
  186. pysage_tools-0.1.0/sage_mods/edain/schema.py +97 -0
  187. pysage_tools-0.1.0/sage_mods/edain/server.py +57 -0
  188. pysage_tools-0.1.0/sage_mods/edain/skill_assets/bfme-faction/SKILL.md +95 -0
  189. pysage_tools-0.1.0/sage_mods/edain/skill_install.py +19 -0
  190. pysage_tools-0.1.0/sage_mods/edain/ui/app.js +494 -0
  191. pysage_tools-0.1.0/sage_mods/edain/ui/index.html +34 -0
  192. pysage_tools-0.1.0/sage_mods/edain/ui/style.css +218 -0
  193. pysage_tools-0.1.0/sage_mods/py.typed +0 -0
  194. pysage_tools-0.1.0/sage_replay/__init__.py +90 -0
  195. pysage_tools-0.1.0/sage_replay/__main__.py +1099 -0
  196. pysage_tools-0.1.0/sage_replay/aggregate.py +3361 -0
  197. pysage_tools-0.1.0/sage_replay/build_orders.py +328 -0
  198. pysage_tools-0.1.0/sage_replay/cache.py +127 -0
  199. pysage_tools-0.1.0/sage_replay/coverage.py +605 -0
  200. pysage_tools-0.1.0/sage_replay/heroes.py +107 -0
  201. pysage_tools-0.1.0/sage_replay/ids.py +239 -0
  202. pysage_tools-0.1.0/sage_replay/narrate.py +726 -0
  203. pysage_tools-0.1.0/sage_replay/py.typed +0 -0
  204. pysage_tools-0.1.0/sage_replay/replay.py +942 -0
  205. pysage_tools-0.1.0/sage_replay/retarget.py +312 -0
  206. pysage_tools-0.1.0/sage_replay/serialize.py +172 -0
  207. pysage_tools-0.1.0/sage_replay/sidecar.py +216 -0
  208. pysage_tools-0.1.0/sage_replay/stats.py +519 -0
  209. pysage_tools-0.1.0/sage_replay/translated.py +701 -0
  210. pysage_tools-0.1.0/sage_replay/winner.py +222 -0
  211. pysage_tools-0.1.0/sage_save/__init__.py +246 -0
  212. pysage_tools-0.1.0/sage_save/__main__.py +654 -0
  213. pysage_tools-0.1.0/sage_save/chunks.py +1821 -0
  214. pysage_tools-0.1.0/sage_save/coverage.py +76 -0
  215. pysage_tools-0.1.0/sage_save/diagnose.py +257 -0
  216. pysage_tools-0.1.0/sage_save/edit.py +170 -0
  217. pysage_tools-0.1.0/sage_save/export.py +262 -0
  218. pysage_tools-0.1.0/sage_save/players.py +87 -0
  219. pysage_tools-0.1.0/sage_save/py.typed +0 -0
  220. pysage_tools-0.1.0/sage_save/reversing.py +128 -0
  221. pysage_tools-0.1.0/sage_save/save.py +160 -0
  222. pysage_tools-0.1.0/sage_save/serialize.py +169 -0
  223. pysage_tools-0.1.0/sage_save/xfer.py +97 -0
  224. pysage_tools-0.1.0/sage_save/xref.py +263 -0
  225. pysage_tools-0.1.0/sage_ui/__init__.py +3 -0
  226. pysage_tools-0.1.0/sage_ui/app.py +22 -0
  227. pysage_tools-0.1.0/sage_ui/browser.py +987 -0
  228. pysage_tools-0.1.0/sage_ui/extract.py +243 -0
  229. pysage_tools-0.1.0/sage_ui/icon.ico +0 -0
  230. pysage_tools-0.1.0/sage_ui/layout.py +11 -0
  231. pysage_tools-0.1.0/sage_ui/object_browser.py +386 -0
  232. pysage_tools-0.1.0/sage_ui/registry.py +106 -0
  233. pysage_tools-0.1.0/sage_ui/unit_panel.py +1263 -0
  234. pysage_tools-0.1.0/sage_utils/__init__.py +4 -0
  235. pysage_tools-0.1.0/sage_utils/assets/active_overlay.png +0 -0
  236. pysage_tools-0.1.0/sage_utils/assets/background.png +0 -0
  237. pysage_tools-0.1.0/sage_utils/assets/passive_overlay.png +0 -0
  238. pysage_tools-0.1.0/sage_utils/cli.py +110 -0
  239. pysage_tools-0.1.0/sage_utils/clock.py +18 -0
  240. pysage_tools-0.1.0/sage_utils/config.py +40 -0
  241. pysage_tools-0.1.0/sage_utils/extras.py +39 -0
  242. pysage_tools-0.1.0/sage_utils/factiongraph/__init__.py +77 -0
  243. pysage_tools-0.1.0/sage_utils/factiongraph/bases.py +149 -0
  244. pysage_tools-0.1.0/sage_utils/factiongraph/graph.py +637 -0
  245. pysage_tools-0.1.0/sage_utils/factiongraph/model.py +268 -0
  246. pysage_tools-0.1.0/sage_utils/factiongraph/powers.py +135 -0
  247. pysage_tools-0.1.0/sage_utils/factiongraph/profile.py +123 -0
  248. pysage_tools-0.1.0/sage_utils/findings.py +187 -0
  249. pysage_tools-0.1.0/sage_utils/gameroot.py +46 -0
  250. pysage_tools-0.1.0/sage_utils/refpack.py +354 -0
  251. pysage_tools-0.1.0/sage_utils/skill.py +41 -0
  252. pysage_tools-0.1.0/sage_utils/sources.py +203 -0
  253. pysage_tools-0.1.0/sage_utils/stream.py +410 -0
  254. pysage_tools-0.1.0/sage_utils/styles.py +106 -0
  255. pysage_tools-0.1.0/sage_utils/textures.py +212 -0
  256. pysage_tools-0.1.0/sage_utils/views/__init__.py +130 -0
  257. pysage_tools-0.1.0/sage_utils/views/base.py +52 -0
  258. pysage_tools-0.1.0/sage_utils/views/buttons.py +194 -0
  259. pysage_tools-0.1.0/sage_utils/views/factions.py +169 -0
  260. pysage_tools-0.1.0/sage_utils/views/objects.py +55 -0
  261. pysage_tools-0.1.0/sage_utils/views/powers.py +209 -0
  262. pysage_tools-0.1.0/sage_utils/views/text.py +113 -0
  263. pysage_tools-0.1.0/sage_utils/views/weapons.py +334 -0
  264. pysage_tools-0.1.0/sage_utils/widgets.py +481 -0
  265. pysage_tools-0.1.0/sage_wiki/__init__.py +4 -0
  266. pysage_tools-0.1.0/sage_wiki/app.py +286 -0
  267. pysage_tools-0.1.0/sage_wiki/archetypes.py +205 -0
  268. pysage_tools-0.1.0/sage_wiki/armorsets.py +94 -0
  269. pysage_tools-0.1.0/sage_wiki/cards/__init__.py +4 -0
  270. pysage_tools-0.1.0/sage_wiki/cards/category_card.py +278 -0
  271. pysage_tools-0.1.0/sage_wiki/cards/diff_card.py +428 -0
  272. pysage_tools-0.1.0/sage_wiki/cards/images_card.py +580 -0
  273. pysage_tools-0.1.0/sage_wiki/cards/pagegen_card.py +204 -0
  274. pysage_tools-0.1.0/sage_wiki/cards/tools_card.py +334 -0
  275. pysage_tools-0.1.0/sage_wiki/credentials.py +61 -0
  276. pysage_tools-0.1.0/sage_wiki/diff.py +137 -0
  277. pysage_tools-0.1.0/sage_wiki/icon.ico +0 -0
  278. pysage_tools-0.1.0/sage_wiki/images.py +166 -0
  279. pysage_tools-0.1.0/sage_wiki/infobox.py +124 -0
  280. pysage_tools-0.1.0/sage_wiki/launcher.py +21 -0
  281. pysage_tools-0.1.0/sage_wiki/links.py +93 -0
  282. pysage_tools-0.1.0/sage_wiki/mapping.py +554 -0
  283. pysage_tools-0.1.0/sage_wiki/meta.py +7 -0
  284. pysage_tools-0.1.0/sage_wiki/names.py +15 -0
  285. pysage_tools-0.1.0/sage_wiki/pagegen.py +682 -0
  286. pysage_tools-0.1.0/sage_wiki/versions.py +35 -0
  287. pysage_tools-0.1.0/sage_wiki/weapons.py +105 -0
  288. pysage_tools-0.1.0/sage_wiki/wiki/__init__.py +5 -0
  289. pysage_tools-0.1.0/sage_wiki/wiki/client.py +217 -0
  290. pysage_tools-0.1.0/setup.cfg +4 -0
  291. pysage_tools-0.1.0/tests/test_packaging.py +82 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Clement Julia
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: pysage-tools
3
+ Version: 0.1.0
4
+ Summary: Python tools for the data formats of the SAGE engine (Battle for Middle-earth): ini game data, binary maps, replays, and UI movies.
5
+ Author-email: Clement Julia <clement.julia13@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ClementJ18/pySAGE
8
+ Project-URL: Repository, https://github.com/ClementJ18/pySAGE
9
+ Project-URL: Issues, https://github.com/ClementJ18/pySAGE/issues
10
+ Keywords: sage,bfme,ini,parser,linter,map,replay,modding
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Classifier: Topic :: Software Development :: Quality Assurance
18
+ Classifier: Topic :: Games/Entertainment
19
+ Requires-Python: >=3.12
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: reversebox>=0.84; sys_platform == "win32"
23
+ Provides-Extra: ui
24
+ Requires-Dist: PyQt6>=6.6; extra == "ui"
25
+ Requires-Dist: pybig>=0.6; extra == "ui"
26
+ Requires-Dist: pillow>=10; extra == "ui"
27
+ Provides-Extra: lint-ui
28
+ Requires-Dist: PyQt6>=6.6; extra == "lint-ui"
29
+ Provides-Extra: wiki
30
+ Requires-Dist: mwclient>=0.11; extra == "wiki"
31
+ Requires-Dist: mwparserfromhell>=0.7; extra == "wiki"
32
+ Requires-Dist: PyQt6>=6.6; extra == "wiki"
33
+ Requires-Dist: pybig>=0.6; extra == "wiki"
34
+ Requires-Dist: keyring>=24; extra == "wiki"
35
+ Provides-Extra: edain-ui
36
+ Requires-Dist: PyQt6>=6.6; extra == "edain-ui"
37
+ Provides-Extra: apt
38
+ Requires-Dist: pybig>=0.6; extra == "apt"
39
+ Dynamic: license-file
40
+
41
+ # pySAGE
42
+
43
+ A collection of Python tools for reading, editing, linting and visualising the data
44
+ formats of the **SAGE engine** - the engine behind *Command & Conquer: Generals* and
45
+ *The Battle for Middle-earth*. It grew out of an ini parser and now spans ini game data,
46
+ binary maps, replays, and UI, with a domain overlay for the Edain mod.
47
+
48
+ Everything installs as one package with optional extras (see [Install](#install)). Each
49
+ subproject has its own README with the details; this page is the map.
50
+
51
+ ## Projects
52
+
53
+ ### Ini game data
54
+
55
+ | Project | What it is |
56
+ | --- | --- |
57
+ | [`sage_ini`](sage_ini/README.md) | The foundation: a typed, comment-preserving `.ini` parser, a whole-game loader, the cross-reference graph, and a lossless AST. Everything else builds on it. |
58
+ | [`sage_lint`](sage_lint/README.md) | Formatter and linter over `sage_ini` - canonical reprint plus judgment rules (dangling references, out-of-range values, duplicates, unused definitions) and meta-analysis. |
59
+
60
+ ### Binary formats
61
+
62
+ | Project | What it is |
63
+ | --- | --- |
64
+ | [`sage_map`](sage_map/README.md) | Reader/writer for BFME `.map` files, plus a game-aware overlay that resolves script arguments and object references and lints maps. |
65
+ | [`sage_replay`](sage_replay/README.md) | Reader for SAGE replay files (Generals `.rep`, BFME / BFME2 / RotWK) - the recorded order stream, decoded into build orders, APM and command timing. |
66
+ | [`sage_apt`](sage_apt/README.md) | Converter, viewer and editor for `.apt` UI movies (the Flash-derived format behind BFME's menus and HUD). **Work in progress**, not yet fully functional. |
67
+
68
+ ### Domain overlays & apps
69
+
70
+ | Project | What it is |
71
+ | --- | --- |
72
+ | [`sage_mods.edain`](sage_mods/edain/README.md) | Edain-mod overlay: builds a faction ownership graph (spellbook → base → structures → units/heroes/upgrades) and renders, diffs or serves it. |
73
+ | [`sage_wiki`](sage_wiki/README.md) | Desktop tool that updates Edain wiki infoboxes from parsed game data through the MediaWiki API. |
74
+ | [`sage_ui`](sage_ui/README.md) | PyQt6 desktop browser for SAGE game data: load sources, search an object, see its resolved stats. |
75
+
76
+ ### Shared
77
+
78
+ | Project | What it is |
79
+ | --- | --- |
80
+ | [`sage_utils`](sage_utils/README.md) | Helpers shared by more than one front end: the Qt-free data layer (sources, textures, views, the faction-graph types) and the shared Qt chrome. |
81
+
82
+ ## Install
83
+
84
+ Requires Python ≥ 3.12. The project is **pySAGE**; on PyPI it is published as **`pysage-tools`**.
85
+
86
+ > **Note:** the bare `pysage` name on PyPI is an unrelated, abandoned messaging library last
87
+ > released in 2011, and `py-sage` is likewise taken by another project. `pip install pysage` will
88
+ > *not* get you this project - install `pysage-tools`.
89
+
90
+ ```sh
91
+ pip install pysage-tools # core library + linter
92
+ pip install "pysage-tools[ui]" # + the PyQt6 desktop apps (sage-ui)
93
+ pip install "pysage-tools[wiki]" # + the wiki updater
94
+ pip install "pysage-tools[edain-ui]" # + the Edain Linter desktop app
95
+ pip install "pysage-tools[apt]" # + reading .const/.apt out of .big archives
96
+ ```
97
+
98
+ From a clone, for development, swap the name for an editable install of the checkout:
99
+
100
+ ```sh
101
+ pip install -e ".[ui]"
102
+ ```
103
+
104
+ The extras (`ui`, `lint-ui`, `wiki`, `edain-ui`, `apt`) pull in the optional dependencies each
105
+ peripheral tool needs. The ini, map and replay layers are stdlib-only and always ship, so no
106
+ extra is needed to parse, lint or diff a map. The one non-optional dependency is `reversebox` on
107
+ Windows, the native RefPack compressor that makes saving large maps fast (its DLL is Windows-only,
108
+ so other platforms use the byte-identical pure-Python compressor).
109
+
110
+ Console scripts are installed for the CLI tools: `sage-ini`, `sage-lint`, `sage-edain`,
111
+ `sage-replay`, `sage-apt` (and the GUI scripts `sage-ui`, `sage-wiki`, `sage-lint-ui`,
112
+ `sage-edain-lint` - the Edain Linter, which combines the ini and map checks in one window).
113
+
114
+ ## Tests
115
+
116
+ ```sh
117
+ pytest # fast, data-free core suite
118
+ pytest --full # + corpus acceptance gates and peripheral-package suites
119
+ ```
120
+
121
+ ## Contributing
122
+
123
+ Contributions are welcome - bug reports, fixes, new checks and rules, format coverage, and
124
+ documentation all help. See **[CONTRIBUTING.md](CONTRIBUTING.md)** to get set up and
125
+ **[CONVENTIONS.md](CONVENTIONS.md)** for the coding rules. AI-assisted contributions are
126
+ welcome too, with one expectation: you have read, understood, and can stand behind every
127
+ line you submit.
@@ -0,0 +1,87 @@
1
+ # pySAGE
2
+
3
+ A collection of Python tools for reading, editing, linting and visualising the data
4
+ formats of the **SAGE engine** - the engine behind *Command & Conquer: Generals* and
5
+ *The Battle for Middle-earth*. It grew out of an ini parser and now spans ini game data,
6
+ binary maps, replays, and UI, with a domain overlay for the Edain mod.
7
+
8
+ Everything installs as one package with optional extras (see [Install](#install)). Each
9
+ subproject has its own README with the details; this page is the map.
10
+
11
+ ## Projects
12
+
13
+ ### Ini game data
14
+
15
+ | Project | What it is |
16
+ | --- | --- |
17
+ | [`sage_ini`](sage_ini/README.md) | The foundation: a typed, comment-preserving `.ini` parser, a whole-game loader, the cross-reference graph, and a lossless AST. Everything else builds on it. |
18
+ | [`sage_lint`](sage_lint/README.md) | Formatter and linter over `sage_ini` - canonical reprint plus judgment rules (dangling references, out-of-range values, duplicates, unused definitions) and meta-analysis. |
19
+
20
+ ### Binary formats
21
+
22
+ | Project | What it is |
23
+ | --- | --- |
24
+ | [`sage_map`](sage_map/README.md) | Reader/writer for BFME `.map` files, plus a game-aware overlay that resolves script arguments and object references and lints maps. |
25
+ | [`sage_replay`](sage_replay/README.md) | Reader for SAGE replay files (Generals `.rep`, BFME / BFME2 / RotWK) - the recorded order stream, decoded into build orders, APM and command timing. |
26
+ | [`sage_apt`](sage_apt/README.md) | Converter, viewer and editor for `.apt` UI movies (the Flash-derived format behind BFME's menus and HUD). **Work in progress**, not yet fully functional. |
27
+
28
+ ### Domain overlays & apps
29
+
30
+ | Project | What it is |
31
+ | --- | --- |
32
+ | [`sage_mods.edain`](sage_mods/edain/README.md) | Edain-mod overlay: builds a faction ownership graph (spellbook → base → structures → units/heroes/upgrades) and renders, diffs or serves it. |
33
+ | [`sage_wiki`](sage_wiki/README.md) | Desktop tool that updates Edain wiki infoboxes from parsed game data through the MediaWiki API. |
34
+ | [`sage_ui`](sage_ui/README.md) | PyQt6 desktop browser for SAGE game data: load sources, search an object, see its resolved stats. |
35
+
36
+ ### Shared
37
+
38
+ | Project | What it is |
39
+ | --- | --- |
40
+ | [`sage_utils`](sage_utils/README.md) | Helpers shared by more than one front end: the Qt-free data layer (sources, textures, views, the faction-graph types) and the shared Qt chrome. |
41
+
42
+ ## Install
43
+
44
+ Requires Python ≥ 3.12. The project is **pySAGE**; on PyPI it is published as **`pysage-tools`**.
45
+
46
+ > **Note:** the bare `pysage` name on PyPI is an unrelated, abandoned messaging library last
47
+ > released in 2011, and `py-sage` is likewise taken by another project. `pip install pysage` will
48
+ > *not* get you this project - install `pysage-tools`.
49
+
50
+ ```sh
51
+ pip install pysage-tools # core library + linter
52
+ pip install "pysage-tools[ui]" # + the PyQt6 desktop apps (sage-ui)
53
+ pip install "pysage-tools[wiki]" # + the wiki updater
54
+ pip install "pysage-tools[edain-ui]" # + the Edain Linter desktop app
55
+ pip install "pysage-tools[apt]" # + reading .const/.apt out of .big archives
56
+ ```
57
+
58
+ From a clone, for development, swap the name for an editable install of the checkout:
59
+
60
+ ```sh
61
+ pip install -e ".[ui]"
62
+ ```
63
+
64
+ The extras (`ui`, `lint-ui`, `wiki`, `edain-ui`, `apt`) pull in the optional dependencies each
65
+ peripheral tool needs. The ini, map and replay layers are stdlib-only and always ship, so no
66
+ extra is needed to parse, lint or diff a map. The one non-optional dependency is `reversebox` on
67
+ Windows, the native RefPack compressor that makes saving large maps fast (its DLL is Windows-only,
68
+ so other platforms use the byte-identical pure-Python compressor).
69
+
70
+ Console scripts are installed for the CLI tools: `sage-ini`, `sage-lint`, `sage-edain`,
71
+ `sage-replay`, `sage-apt` (and the GUI scripts `sage-ui`, `sage-wiki`, `sage-lint-ui`,
72
+ `sage-edain-lint` - the Edain Linter, which combines the ini and map checks in one window).
73
+
74
+ ## Tests
75
+
76
+ ```sh
77
+ pytest # fast, data-free core suite
78
+ pytest --full # + corpus acceptance gates and peripheral-package suites
79
+ ```
80
+
81
+ ## Contributing
82
+
83
+ Contributions are welcome - bug reports, fixes, new checks and rules, format coverage, and
84
+ documentation all help. See **[CONTRIBUTING.md](CONTRIBUTING.md)** to get set up and
85
+ **[CONVENTIONS.md](CONVENTIONS.md)** for the coding rules. AI-assisted contributions are
86
+ welcome too, with one expectation: you have read, understood, and can stand behind every
87
+ line you submit.
@@ -0,0 +1,184 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"] # >=77 for the PEP 639 SPDX `license` field below
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pysage-tools"
7
+ version = "0.1.0"
8
+ description = "Python tools for the data formats of the SAGE engine (Battle for Middle-earth): ini game data, binary maps, replays, and UI movies."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ { name = "Clement Julia", email = "clement.julia13@gmail.com" },
15
+ ]
16
+ keywords = ["sage", "bfme", "ini", "parser", "linter", "map", "replay", "modding"]
17
+ classifiers = [
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: End Users/Desktop",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Topic :: Software Development :: Libraries",
24
+ "Topic :: Software Development :: Quality Assurance",
25
+ "Topic :: Games/Entertainment",
26
+ ]
27
+ dependencies = [
28
+ # Native RefPack compressor for map saving (`sage_utils.refpack`). reversebox ships a
29
+ # Windows-only DLL, so the marker installs it exactly where it can load; every other
30
+ # platform resolves to no dependencies at all and uses the pure-Python compressor.
31
+ "reversebox>=0.84; sys_platform == 'win32'",
32
+ ]
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/ClementJ18/pySAGE"
36
+ Repository = "https://github.com/ClementJ18/pySAGE"
37
+ Issues = "https://github.com/ClementJ18/pySAGE/issues"
38
+
39
+ [project.scripts]
40
+ sage-lint = "sage_lint.cli:main"
41
+ sage-ini = "sage_ini.__main__:main"
42
+ sage-edain = "sage_mods.edain.__main__:main"
43
+ sage-replay = "sage_replay.__main__:main"
44
+ sage-apt = "sage_apt.__main__:main"
45
+ sage-save = "sage_save.__main__:main"
46
+ sage-map = "sage_map.__main__:main"
47
+
48
+ # Desktop apps; each needs its extra installed (ui / wiki / lint-ui / edain-ui).
49
+ [project.gui-scripts]
50
+ sage-ui = "sage_ui.app:main"
51
+ sage-wiki = "sage_wiki.launcher:main" # guards the [wiki] extra; app.py imports Qt at module scope
52
+ sage-lint-ui = "sage_lint.plugins.ui.app:main"
53
+ sage-edain-lint = "sage_mods.edain.map_checks.ui.app:main"
54
+
55
+ [project.optional-dependencies]
56
+ ui = [
57
+ "PyQt6>=6.6",
58
+ "pybig>=0.6",
59
+ "pillow>=10",
60
+ ]
61
+
62
+ lint-ui = [
63
+ "PyQt6>=6.6",
64
+ ]
65
+
66
+ wiki = [
67
+ "mwclient>=0.11",
68
+ "mwparserfromhell>=0.7",
69
+ "PyQt6>=6.6",
70
+ "pybig>=0.6",
71
+ "keyring>=24",
72
+ ]
73
+
74
+ edain-ui = [
75
+ "PyQt6>=6.6",
76
+ ]
77
+
78
+ apt = [
79
+ "pybig>=0.6", # reading a .const (or .apt) out of a .big archive; the core stays stdlib-only
80
+ ]
81
+
82
+ [dependency-groups]
83
+ dev = [
84
+ "pytest",
85
+ "ruff",
86
+ "mypy",
87
+ "pyinstaller>=6", # builds the desktop .exe bundles (the *.spec files); not a runtime dep
88
+ ]
89
+
90
+ [tool.setuptools.packages.find]
91
+ include = ["sage_apt*", "sage_ini*", "sage_lint*", "sage_map*", "sage_replay*", "sage_save*", "sage_utils*", "sage_wiki*", "sage_ui*", "sage_mods*"]
92
+
93
+ [tool.setuptools.package-data]
94
+ # Anything a package opens at runtime must be listed here, or it is absent from the wheel. The
95
+ # loaders degrade silently (a missing asset returns None), so an omission surfaces as a feature
96
+ # quietly not working rather than an error; tests/test_packaging.py asserts every runtime asset
97
+ # below is shipped.
98
+ sage_apt = ["assets/*.html", "py.typed"]
99
+ sage_ini = ["py.typed", "skill_assets/**/*"]
100
+ sage_map = ["py.typed"]
101
+ sage_save = ["py.typed"]
102
+ sage_replay = ["py.typed"]
103
+ sage_ui = ["*.ico"]
104
+ sage_wiki = ["*.ico"]
105
+ sage_utils = ["assets/*.png"] # portrait background + overlays; sage_utils/textures.py
106
+ "sage_lint.plugins.ui" = ["*.ico"]
107
+ sage_mods = ["py.typed"] # PEP 561 marker belongs on the top-level package, not sage_mods.edain
108
+ "sage_mods.edain" = [
109
+ "ui/*",
110
+ "skill_assets/**/*",
111
+ "map_checks/ui/*.ico",
112
+ "icons/*.webp", # faction emblems; the public ICONS_DIR / FACTION_ICONS in edain/replay.py
113
+ ]
114
+
115
+ [tool.pytest.ini_options]
116
+ testpaths = ["tests"]
117
+ pythonpath = ["."]
118
+ markers = [
119
+ "full: part of the full suite (corpus gates + peripheral packages); run with --full",
120
+ ]
121
+
122
+ [tool.ruff]
123
+ target-version = "py312" # matches requires-python, so pyupgrade cannot suggest 3.13-only syntax
124
+ line-length = 100
125
+ extend-exclude = [
126
+ "data", # game-data corpus
127
+ ]
128
+
129
+ [tool.ruff.lint]
130
+ select = [
131
+ "E", # pycodestyle errors (E722: no bare `except:`)
132
+ "W", # pycodestyle warnings
133
+ "F", # pyflakes
134
+ "I", # isort - deterministic import order
135
+ "B", # bugbear (B009/B010: no getattr/setattr with constant attribute names)
136
+ "UP", # pyupgrade
137
+ "BLE", # blind-except: no `except Exception:` swallowing
138
+ "PLC0415", # all imports at module top level; no function-local imports
139
+ ]
140
+
141
+ [tool.ruff.lint.per-file-ignores]
142
+ "sage_ini/model/behaviors.py" = ["F821"]
143
+ "sage_ini/model/nuggets.py" = ["F821"]
144
+ "sage_ini/model/data_blocks.py" = ["F821"]
145
+ # The embedded single-page HTML/CSS/JS template carries lines longer than the Python limit.
146
+ "sage_apt/viewer.py" = ["E501"]
147
+ "sage_replay/aggregate.py" = ["E501"]
148
+
149
+ [tool.ruff.format]
150
+
151
+ [tool.mypy]
152
+ python_version = "3.12" # matches requires-python: catch 3.13-only API use on the lowest floor
153
+ files = ["sage_apt", "sage_ini", "sage_map", "sage_mods", "sage_replay", "sage_save", "sage_utils"]
154
+ disable_error_code = ["annotation-unchecked"]
155
+
156
+ [[tool.mypy.overrides]]
157
+ module = ["reversebox.*", "PyQt6.*", "pyBIG.*", "PIL.*"]
158
+ ignore_missing_imports = true
159
+
160
+ # The Qt half of sage_utils (and the texture/source layer built on optional deps) is outside
161
+ # the type-checked set: it needs the [ui] extras installed and predates annotations. The
162
+ # Qt-free helpers (config, views, skill, cli) are checked like the core packages.
163
+ [[tool.mypy.overrides]]
164
+ module = [
165
+ "sage_utils.widgets",
166
+ "sage_utils.styles",
167
+ "sage_utils.textures",
168
+ "sage_utils.sources",
169
+ "sage_utils.findings",
170
+ ]
171
+ ignore_errors = true
172
+
173
+ # Same for the Qt half of the Edain Linter window; its Qt-free runner stays checked.
174
+ [[tool.mypy.overrides]]
175
+ module = ["sage_mods.edain.map_checks.ui.window", "sage_mods.edain.map_checks.ui.app"]
176
+ ignore_errors = true
177
+
178
+ # sage_lint is a tool package, not in the type-checked `files` set. sage_mods.edain.map_checks imports
179
+ # its shared map-lint runner (add_map_lint_arguments / run_map_lint), which pulls sage_lint into
180
+ # reach: follow the import so sage_mods.edain still sees real types, but don't gate on sage_lint's own
181
+ # (pre-existing) errors here - it is checked on its own terms, not through this overlay.
182
+ [[tool.mypy.overrides]]
183
+ module = ["sage_lint.*"]
184
+ follow_imports = "silent"
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: pysage-tools
3
+ Version: 0.1.0
4
+ Summary: Python tools for the data formats of the SAGE engine (Battle for Middle-earth): ini game data, binary maps, replays, and UI movies.
5
+ Author-email: Clement Julia <clement.julia13@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ClementJ18/pySAGE
8
+ Project-URL: Repository, https://github.com/ClementJ18/pySAGE
9
+ Project-URL: Issues, https://github.com/ClementJ18/pySAGE/issues
10
+ Keywords: sage,bfme,ini,parser,linter,map,replay,modding
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Classifier: Topic :: Software Development :: Quality Assurance
18
+ Classifier: Topic :: Games/Entertainment
19
+ Requires-Python: >=3.12
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: reversebox>=0.84; sys_platform == "win32"
23
+ Provides-Extra: ui
24
+ Requires-Dist: PyQt6>=6.6; extra == "ui"
25
+ Requires-Dist: pybig>=0.6; extra == "ui"
26
+ Requires-Dist: pillow>=10; extra == "ui"
27
+ Provides-Extra: lint-ui
28
+ Requires-Dist: PyQt6>=6.6; extra == "lint-ui"
29
+ Provides-Extra: wiki
30
+ Requires-Dist: mwclient>=0.11; extra == "wiki"
31
+ Requires-Dist: mwparserfromhell>=0.7; extra == "wiki"
32
+ Requires-Dist: PyQt6>=6.6; extra == "wiki"
33
+ Requires-Dist: pybig>=0.6; extra == "wiki"
34
+ Requires-Dist: keyring>=24; extra == "wiki"
35
+ Provides-Extra: edain-ui
36
+ Requires-Dist: PyQt6>=6.6; extra == "edain-ui"
37
+ Provides-Extra: apt
38
+ Requires-Dist: pybig>=0.6; extra == "apt"
39
+ Dynamic: license-file
40
+
41
+ # pySAGE
42
+
43
+ A collection of Python tools for reading, editing, linting and visualising the data
44
+ formats of the **SAGE engine** - the engine behind *Command & Conquer: Generals* and
45
+ *The Battle for Middle-earth*. It grew out of an ini parser and now spans ini game data,
46
+ binary maps, replays, and UI, with a domain overlay for the Edain mod.
47
+
48
+ Everything installs as one package with optional extras (see [Install](#install)). Each
49
+ subproject has its own README with the details; this page is the map.
50
+
51
+ ## Projects
52
+
53
+ ### Ini game data
54
+
55
+ | Project | What it is |
56
+ | --- | --- |
57
+ | [`sage_ini`](sage_ini/README.md) | The foundation: a typed, comment-preserving `.ini` parser, a whole-game loader, the cross-reference graph, and a lossless AST. Everything else builds on it. |
58
+ | [`sage_lint`](sage_lint/README.md) | Formatter and linter over `sage_ini` - canonical reprint plus judgment rules (dangling references, out-of-range values, duplicates, unused definitions) and meta-analysis. |
59
+
60
+ ### Binary formats
61
+
62
+ | Project | What it is |
63
+ | --- | --- |
64
+ | [`sage_map`](sage_map/README.md) | Reader/writer for BFME `.map` files, plus a game-aware overlay that resolves script arguments and object references and lints maps. |
65
+ | [`sage_replay`](sage_replay/README.md) | Reader for SAGE replay files (Generals `.rep`, BFME / BFME2 / RotWK) - the recorded order stream, decoded into build orders, APM and command timing. |
66
+ | [`sage_apt`](sage_apt/README.md) | Converter, viewer and editor for `.apt` UI movies (the Flash-derived format behind BFME's menus and HUD). **Work in progress**, not yet fully functional. |
67
+
68
+ ### Domain overlays & apps
69
+
70
+ | Project | What it is |
71
+ | --- | --- |
72
+ | [`sage_mods.edain`](sage_mods/edain/README.md) | Edain-mod overlay: builds a faction ownership graph (spellbook → base → structures → units/heroes/upgrades) and renders, diffs or serves it. |
73
+ | [`sage_wiki`](sage_wiki/README.md) | Desktop tool that updates Edain wiki infoboxes from parsed game data through the MediaWiki API. |
74
+ | [`sage_ui`](sage_ui/README.md) | PyQt6 desktop browser for SAGE game data: load sources, search an object, see its resolved stats. |
75
+
76
+ ### Shared
77
+
78
+ | Project | What it is |
79
+ | --- | --- |
80
+ | [`sage_utils`](sage_utils/README.md) | Helpers shared by more than one front end: the Qt-free data layer (sources, textures, views, the faction-graph types) and the shared Qt chrome. |
81
+
82
+ ## Install
83
+
84
+ Requires Python ≥ 3.12. The project is **pySAGE**; on PyPI it is published as **`pysage-tools`**.
85
+
86
+ > **Note:** the bare `pysage` name on PyPI is an unrelated, abandoned messaging library last
87
+ > released in 2011, and `py-sage` is likewise taken by another project. `pip install pysage` will
88
+ > *not* get you this project - install `pysage-tools`.
89
+
90
+ ```sh
91
+ pip install pysage-tools # core library + linter
92
+ pip install "pysage-tools[ui]" # + the PyQt6 desktop apps (sage-ui)
93
+ pip install "pysage-tools[wiki]" # + the wiki updater
94
+ pip install "pysage-tools[edain-ui]" # + the Edain Linter desktop app
95
+ pip install "pysage-tools[apt]" # + reading .const/.apt out of .big archives
96
+ ```
97
+
98
+ From a clone, for development, swap the name for an editable install of the checkout:
99
+
100
+ ```sh
101
+ pip install -e ".[ui]"
102
+ ```
103
+
104
+ The extras (`ui`, `lint-ui`, `wiki`, `edain-ui`, `apt`) pull in the optional dependencies each
105
+ peripheral tool needs. The ini, map and replay layers are stdlib-only and always ship, so no
106
+ extra is needed to parse, lint or diff a map. The one non-optional dependency is `reversebox` on
107
+ Windows, the native RefPack compressor that makes saving large maps fast (its DLL is Windows-only,
108
+ so other platforms use the byte-identical pure-Python compressor).
109
+
110
+ Console scripts are installed for the CLI tools: `sage-ini`, `sage-lint`, `sage-edain`,
111
+ `sage-replay`, `sage-apt` (and the GUI scripts `sage-ui`, `sage-wiki`, `sage-lint-ui`,
112
+ `sage-edain-lint` - the Edain Linter, which combines the ini and map checks in one window).
113
+
114
+ ## Tests
115
+
116
+ ```sh
117
+ pytest # fast, data-free core suite
118
+ pytest --full # + corpus acceptance gates and peripheral-package suites
119
+ ```
120
+
121
+ ## Contributing
122
+
123
+ Contributions are welcome - bug reports, fixes, new checks and rules, format coverage, and
124
+ documentation all help. See **[CONTRIBUTING.md](CONTRIBUTING.md)** to get set up and
125
+ **[CONVENTIONS.md](CONVENTIONS.md)** for the coding rules. AI-assisted contributions are
126
+ welcome too, with one expectation: you have read, understood, and can stand behind every
127
+ line you submit.