cogames 0.3.68__tar.gz → 0.3.70__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 (207) hide show
  1. {cogames-0.3.68/src/cogames.egg-info → cogames-0.3.70}/PKG-INFO +2 -2
  2. {cogames-0.3.68 → cogames-0.3.70}/pyproject.toml +1 -1
  3. cogames-0.3.70/src/cogames/cli/submit.py +331 -0
  4. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/main.py +79 -49
  5. {cogames-0.3.68 → cogames-0.3.70/src/cogames.egg-info}/PKG-INFO +2 -2
  6. {cogames-0.3.68 → cogames-0.3.70}/src/cogames.egg-info/requires.txt +1 -1
  7. {cogames-0.3.68 → cogames-0.3.70}/tests/test_upload_cli.py +42 -36
  8. {cogames-0.3.68 → cogames-0.3.70}/tests/test_upload_policy_bundles.py +13 -24
  9. cogames-0.3.68/src/cogames/cli/submit.py +0 -611
  10. {cogames-0.3.68 → cogames-0.3.70}/CHANGELOG.md +0 -0
  11. {cogames-0.3.68 → cogames-0.3.70}/LICENSE +0 -0
  12. {cogames-0.3.68 → cogames-0.3.70}/MISSION.md +0 -0
  13. {cogames-0.3.68 → cogames-0.3.70}/README.ipynb +0 -0
  14. {cogames-0.3.68 → cogames-0.3.70}/README.md +0 -0
  15. {cogames-0.3.68 → cogames-0.3.70}/README.py +0 -0
  16. {cogames-0.3.68 → cogames-0.3.70}/TECHNICAL_MANUAL.md +0 -0
  17. {cogames-0.3.68 → cogames-0.3.70}/assets/charger.png +0 -0
  18. {cogames-0.3.68 → cogames-0.3.70}/assets/cvc-reel.gif +0 -0
  19. {cogames-0.3.68 → cogames-0.3.70}/assets/cvc-snap.png +0 -0
  20. {cogames-0.3.68 → cogames-0.3.70}/assets/extractor.png +0 -0
  21. {cogames-0.3.68 → cogames-0.3.70}/assets/hub.png +0 -0
  22. {cogames-0.3.68 → cogames-0.3.70}/assets/showoff.gif +0 -0
  23. {cogames-0.3.68 → cogames-0.3.70}/setup.cfg +0 -0
  24. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/__init__.py +0 -0
  25. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/auth.py +0 -0
  26. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/base.py +0 -0
  27. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/client.py +0 -0
  28. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/docsync/__init__.py +0 -0
  29. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/docsync/_nb_md_directive_processing.py +0 -0
  30. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/docsync/_nb_md_sync.py +0 -0
  31. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/docsync/_nb_py_sync.py +0 -0
  32. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/docsync/_three_way_sync.py +0 -0
  33. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/docsync/_utils.py +0 -0
  34. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/docsync/docsync.py +0 -0
  35. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/leaderboard.py +0 -0
  36. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/login.py +0 -0
  37. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/mission.py +0 -0
  38. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/policy.py +0 -0
  39. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cli/utils.py +0 -0
  40. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/__init__.py +0 -0
  41. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/clip_difficulty.py +0 -0
  42. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/clips.py +0 -0
  43. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/cog.py +0 -0
  44. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/cogsguard_curriculum.py +0 -0
  45. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/cogsguard_tutorial.py +0 -0
  46. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/config.py +0 -0
  47. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/docs/cogs_vs_clips_mapgen.md +0 -0
  48. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/evals/README.md +0 -0
  49. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/evals/cogsguard_evals.py +0 -0
  50. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/evals/diagnostic_evals.py +0 -0
  51. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/evals/difficulty_variants.py +0 -0
  52. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/evals/integrated_evals.py +0 -0
  53. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/evals/spanning_evals.py +0 -0
  54. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/mission.py +0 -0
  55. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/missions.py +0 -0
  56. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/reward_variants.py +0 -0
  57. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/sites.py +0 -0
  58. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/stations.py +0 -0
  59. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/team.py +0 -0
  60. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/terrain.py +0 -0
  61. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/variants.py +0 -0
  62. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/cogs_vs_clips/weather.py +0 -0
  63. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/core.py +0 -0
  64. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/curricula.py +0 -0
  65. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/device.py +0 -0
  66. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/docs/SCRIPTED_AGENT.md +0 -0
  67. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/evaluate.py +0 -0
  68. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/game.py +0 -0
  69. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate1_1000.map +0 -0
  70. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate1_1000_stations.map +0 -0
  71. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate1_500.map +0 -0
  72. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate1_500_stations.map +0 -0
  73. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate2_1000.map +0 -0
  74. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate2_1000_stations.map +0 -0
  75. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate2_500.map +0 -0
  76. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate2_500_stations.map +0 -0
  77. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate3_1000.map +0 -0
  78. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate3_1000_stations.map +0 -0
  79. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate3_500.map +0 -0
  80. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate3_500_stations.map +0 -0
  81. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate4_500.map +0 -0
  82. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/canidate4_500_stations.map +0 -0
  83. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/cave_base_50.map +0 -0
  84. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_agile.map +0 -0
  85. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_agile_hard.map +0 -0
  86. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_charge_up.map +0 -0
  87. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_charge_up_hard.map +0 -0
  88. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_navigation1.map +0 -0
  89. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_navigation1_hard.map +0 -0
  90. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_navigation2.map +0 -0
  91. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_navigation2_hard.map +0 -0
  92. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_navigation3.map +0 -0
  93. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_navigation3_hard.map +0 -0
  94. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_near.map +0 -0
  95. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_search.map +0 -0
  96. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_chest_search_hard.map +0 -0
  97. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_extract_lab.map +0 -0
  98. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_extract_lab_hard.map +0 -0
  99. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_memory.map +0 -0
  100. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_memory_hard.map +0 -0
  101. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_radial.map +0 -0
  102. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_radial_hard.map +0 -0
  103. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_resource_lab.map +0 -0
  104. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/diagnostic_evals/diagnostic_unclip.map +0 -0
  105. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_balanced_spread.map +0 -0
  106. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_clip_oxygen.map +0 -0
  107. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_collect_resources.map +0 -0
  108. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_collect_resources_hard.map +0 -0
  109. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_collect_resources_medium.map +0 -0
  110. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_divide_and_conquer.map +0 -0
  111. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_energy_starved.map +0 -0
  112. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_multi_coordinated_collect_hard.map +0 -0
  113. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_oxygen_bottleneck.map +0 -0
  114. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/eval_single_use_world.map +0 -0
  115. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/extractor_hub_100x100.map +0 -0
  116. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/extractor_hub_30x30.map +0 -0
  117. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/extractor_hub_50x50.map +0 -0
  118. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/extractor_hub_70x70.map +0 -0
  119. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/evals/extractor_hub_80x80.map +0 -0
  120. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machina_100_stations.map +0 -0
  121. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machina_200_stations.map +0 -0
  122. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machina_200_stations_small.map +0 -0
  123. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machina_eval_exp01.map +0 -0
  124. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machina_eval_template_large.map +0 -0
  125. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machinatrainer4agents.map +0 -0
  126. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machinatrainer4agentsbase.map +0 -0
  127. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machinatrainerbig.map +0 -0
  128. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/machinatrainersmall.map +0 -0
  129. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/aligner_avoid_aoe.map +0 -0
  130. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/aligner_full_cycle.map +0 -0
  131. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/aligner_gear.map +0 -0
  132. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/aligner_hearts.map +0 -0
  133. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/aligner_junction.map +0 -0
  134. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/exploration_distant.map +0 -0
  135. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/maze.map +0 -0
  136. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/miner_best_resource.map +0 -0
  137. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/miner_deposit.map +0 -0
  138. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/miner_extract.map +0 -0
  139. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/miner_full_cycle.map +0 -0
  140. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/miner_gear.map +0 -0
  141. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/multi_role.map +0 -0
  142. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/resource_chain.map +0 -0
  143. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/scout_explore.map +0 -0
  144. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/scout_gear.map +0 -0
  145. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/scrambler_full_cycle.map +0 -0
  146. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/scrambler_gear.map +0 -0
  147. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/scrambler_target.map +0 -0
  148. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/stuck_corridor.map +0 -0
  149. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/planky_evals/survive_retreat.map +0 -0
  150. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/training_facility_clipped.map +0 -0
  151. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/training_facility_open_1.map +0 -0
  152. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/training_facility_open_2.map +0 -0
  153. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/training_facility_open_3.map +0 -0
  154. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/training_facility_tight_4.map +0 -0
  155. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/training_facility_tight_5.map +0 -0
  156. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/vanilla_large.map +0 -0
  157. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/vanilla_small.map +0 -0
  158. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/maps/zelda.map +0 -0
  159. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/pickup.py +0 -0
  160. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/play.py +0 -0
  161. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/__init__.py +0 -0
  162. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/chaos_monkey.py +0 -0
  163. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/nim_agents/__init__.py +0 -0
  164. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/nim_agents/agents.py +0 -0
  165. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/nim_agents/thinky_eval.py +0 -0
  166. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/pufferlib_policy.py +0 -0
  167. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/signal_handler.py +0 -0
  168. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/starter_agent.py +0 -0
  169. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/policy/trainable_policy_template.py +0 -0
  170. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/py.typed +0 -0
  171. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/train.py +0 -0
  172. {cogames-0.3.68 → cogames-0.3.70}/src/cogames/verbose.py +0 -0
  173. {cogames-0.3.68 → cogames-0.3.70}/src/cogames.egg-info/SOURCES.txt +0 -0
  174. {cogames-0.3.68 → cogames-0.3.70}/src/cogames.egg-info/dependency_links.txt +0 -0
  175. {cogames-0.3.68 → cogames-0.3.70}/src/cogames.egg-info/entry_points.txt +0 -0
  176. {cogames-0.3.68 → cogames-0.3.70}/src/cogames.egg-info/top_level.txt +0 -0
  177. {cogames-0.3.68 → cogames-0.3.70}/src/metta_alo/__init__.py +0 -0
  178. {cogames-0.3.68 → cogames-0.3.70}/src/metta_alo/py.typed +0 -0
  179. {cogames-0.3.68 → cogames-0.3.70}/src/metta_alo/scoring.py +0 -0
  180. {cogames-0.3.68 → cogames-0.3.70}/tests/docsync/conftest.py +0 -0
  181. {cogames-0.3.68 → cogames-0.3.70}/tests/docsync/helpers.py +0 -0
  182. {cogames-0.3.68 → cogames-0.3.70}/tests/docsync/test_docsync_all.py +0 -0
  183. {cogames-0.3.68 → cogames-0.3.70}/tests/docsync/test_docsync_check.py +0 -0
  184. {cogames-0.3.68 → cogames-0.3.70}/tests/docsync/test_docsync_nb_to_md.py +0 -0
  185. {cogames-0.3.68 → cogames-0.3.70}/tests/docsync/test_docsync_nb_to_py.py +0 -0
  186. {cogames-0.3.68 → cogames-0.3.70}/tests/docsync/test_docsync_py_to_nb.py +0 -0
  187. {cogames-0.3.68 → cogames-0.3.70}/tests/metta_alo/test_scoring.py +0 -0
  188. {cogames-0.3.68 → cogames-0.3.70}/tests/test_all_games_describe.py +0 -0
  189. {cogames-0.3.68 → cogames-0.3.70}/tests/test_all_games_eval.py +0 -0
  190. {cogames-0.3.68 → cogames-0.3.70}/tests/test_all_games_play.py +0 -0
  191. {cogames-0.3.68 → cogames-0.3.70}/tests/test_chaos_monkey.py +0 -0
  192. {cogames-0.3.68 → cogames-0.3.70}/tests/test_cli.py +0 -0
  193. {cogames-0.3.68 → cogames-0.3.70}/tests/test_cogs_vs_clips.py +0 -0
  194. {cogames-0.3.68 → cogames-0.3.70}/tests/test_cogsguard_eval_missions.py +0 -0
  195. {cogames-0.3.68 → cogames-0.3.70}/tests/test_policy_cli_parsing.py +0 -0
  196. {cogames-0.3.68 → cogames-0.3.70}/tests/test_procedural_maps.py +0 -0
  197. {cogames-0.3.68 → cogames-0.3.70}/tests/test_train_integration.py +0 -0
  198. {cogames-0.3.68 → cogames-0.3.70}/tests/test_train_vector_alignment.py +0 -0
  199. {cogames-0.3.68 → cogames-0.3.70}/tutorials/01_MAKE_POLICY.ipynb +0 -0
  200. {cogames-0.3.68 → cogames-0.3.70}/tutorials/01_MAKE_POLICY.md +0 -0
  201. {cogames-0.3.68 → cogames-0.3.70}/tutorials/01_MAKE_POLICY.py +0 -0
  202. {cogames-0.3.68 → cogames-0.3.70}/tutorials/02_TRAIN.ipynb +0 -0
  203. {cogames-0.3.68 → cogames-0.3.70}/tutorials/02_TRAIN.md +0 -0
  204. {cogames-0.3.68 → cogames-0.3.70}/tutorials/02_TRAIN.py +0 -0
  205. {cogames-0.3.68 → cogames-0.3.70}/tutorials/03_SUBMIT.ipynb +0 -0
  206. {cogames-0.3.68 → cogames-0.3.70}/tutorials/03_SUBMIT.md +0 -0
  207. {cogames-0.3.68 → cogames-0.3.70}/tutorials/03_SUBMIT.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cogames
3
- Version: 0.3.68
3
+ Version: 0.3.70
4
4
  Summary: Multi-agent cooperative games
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.12
7
7
  Requires-Python: <3.13,>=3.12
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
- Requires-Dist: mettagrid==0.2.0.82
10
+ Requires-Dist: mettagrid==0.2.0.84
11
11
  Requires-Dist: packaging>=24.0.0
12
12
  Requires-Dist: pufferlib-core
13
13
  Requires-Dist: pydantic>=2.11.5
@@ -9,7 +9,7 @@ readme = "README.md"
9
9
  requires-python = ">=3.12,<3.13"
10
10
  classifiers = ["Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12"]
11
11
  dependencies = [
12
- "mettagrid==0.2.0.82",
12
+ "mettagrid==0.2.0.84",
13
13
  "packaging>=24.0.0",
14
14
  "pufferlib-core",
15
15
  "pydantic>=2.11.5",
@@ -0,0 +1,331 @@
1
+ """Policy submission command for CoGames."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ import tempfile
10
+ import uuid
11
+ import zipfile
12
+ from dataclasses import dataclass
13
+ from pathlib import Path
14
+
15
+ import httpx
16
+ import typer
17
+
18
+ from cogames.cli.base import console
19
+ from cogames.cli.client import TournamentServerClient
20
+ from cogames.cli.login import DEFAULT_COGAMES_SERVER
21
+ from cogames.cli.policy import PolicySpec, get_policy_spec
22
+ from mettagrid.config.mettagrid_config import MettaGridConfig
23
+ from mettagrid.policy.submission import POLICY_SPEC_FILENAME, SubmissionPolicySpec
24
+ from mettagrid.runner.episode_runner import run_episode_isolated
25
+ from mettagrid.runner.types import EpisodeSpec
26
+ from mettagrid.util.uri_resolvers.schemes import localize_uri, parse_uri
27
+
28
+ DEFAULT_SUBMIT_SERVER = "https://api.observatory.softmax-research.net"
29
+ RESULTS_URL = "https://www.softmax.com/alignmentleague"
30
+
31
+
32
+ @dataclass
33
+ class UploadResult:
34
+ policy_version_id: uuid.UUID
35
+ name: str
36
+ version: int
37
+ pools: list[str] | None = None
38
+
39
+
40
+ def _resolve_path_within_cwd(path_str: str, cwd: Path) -> Path:
41
+ """Resolve a path and return it relative to CWD. Raises if path escapes CWD."""
42
+ raw_path = Path(path_str).expanduser()
43
+ resolved = raw_path.resolve() if raw_path.is_absolute() else (cwd / raw_path).resolve()
44
+ if not resolved.is_relative_to(cwd):
45
+ console.print(f"[red]Error:[/red] Path must be within the current directory: {path_str}")
46
+ raise ValueError(f"Path escapes CWD: {path_str}")
47
+ return resolved.relative_to(cwd)
48
+
49
+
50
+ def validate_paths(paths: list[str]) -> list[Path]:
51
+ """Validate paths exist and are within CWD, return them as relative paths."""
52
+ cwd = Path.cwd().resolve()
53
+ validated_paths = []
54
+ for path_str in paths:
55
+ relative = _resolve_path_within_cwd(path_str, cwd)
56
+ resolved = cwd / relative
57
+ if not resolved.exists():
58
+ console.print(f"[red]Error:[/red] Path does not exist: {path_str}")
59
+ raise FileNotFoundError(f"Path not found: {path_str}")
60
+ validated_paths.append(relative)
61
+ return validated_paths
62
+
63
+
64
+ def _zip_directory_to(src: Path, dest: Path) -> None:
65
+ with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as zipf:
66
+ for file_path in src.rglob("*"):
67
+ if file_path.is_file():
68
+ zipf.write(file_path, arcname=file_path.relative_to(src))
69
+
70
+
71
+ def _collect_ancestor_init_files(include_files: list[Path]) -> list[Path]:
72
+ found: set[Path] = set()
73
+ for path in include_files:
74
+ parent = path.parent
75
+ while parent != Path(".") and parent != parent.parent:
76
+ init = parent / "__init__.py"
77
+ if init.is_file():
78
+ found.add(init)
79
+ parent = parent.parent
80
+ return sorted(found)
81
+
82
+
83
+ def create_submission_zip(
84
+ include_files: list[Path],
85
+ policy_spec: PolicySpec,
86
+ setup_script: str | None = None,
87
+ ) -> Path:
88
+ """Create a zip file containing all include-files.
89
+
90
+ Maintains directory structure exactly as provided.
91
+ Returns path to created zip file.
92
+ """
93
+ zip_fd, zip_path = tempfile.mkstemp(suffix=".zip", prefix="cogames_submission_")
94
+ os.close(zip_fd)
95
+
96
+ submission_spec = SubmissionPolicySpec(
97
+ class_path=policy_spec.class_path,
98
+ data_path=policy_spec.data_path,
99
+ init_kwargs=policy_spec.init_kwargs,
100
+ setup_script=setup_script,
101
+ )
102
+
103
+ all_files: dict[str, Path] = {}
104
+ for init_path in _collect_ancestor_init_files(include_files):
105
+ all_files[str(init_path)] = init_path
106
+ for file_path in include_files:
107
+ if file_path.is_dir():
108
+ for root, _, files in os.walk(file_path):
109
+ for file in files:
110
+ full = Path(root) / file
111
+ all_files[str(full)] = full
112
+ else:
113
+ all_files[str(file_path)] = file_path
114
+
115
+ with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
116
+ zipf.writestr(data=submission_spec.model_dump_json(), zinfo_or_arcname=POLICY_SPEC_FILENAME)
117
+ for arcname, path in all_files.items():
118
+ zipf.write(path, arcname=arcname)
119
+
120
+ return Path(zip_path)
121
+
122
+
123
+ def create_bundle(
124
+ ctx: typer.Context,
125
+ policy: str,
126
+ output: Path,
127
+ include_files: list[str] | None = None,
128
+ init_kwargs: dict[str, str] | None = None,
129
+ setup_script: str | None = None,
130
+ ) -> Path:
131
+ # TODO: Unify the two paths below. For URI inputs, extract the PolicySpec from the
132
+ # bundle so we can apply init_kwargs/include_files/setup_script, then re-zip.
133
+ local = localize_uri(policy) if parse_uri(policy, allow_none=True, default_scheme=None) else None
134
+ if local is not None:
135
+ if init_kwargs or include_files or setup_script:
136
+ console.print("[red]Error:[/red] Extra files/kwargs are not supported with bundle URIs.")
137
+ raise typer.Exit(1)
138
+ console.print(f"[dim]Packaging existing bundle: {local}[/dim]")
139
+ if local.is_dir():
140
+ _zip_directory_to(local, output)
141
+ else:
142
+ shutil.copy2(local, output)
143
+ console.print(f"[dim]Bundle size: {output.stat().st_size / 1024:.0f} KB[/dim]")
144
+ return output
145
+
146
+ policy_spec = get_policy_spec(ctx, policy)
147
+ console.print(f"[dim]Policy class: {policy_spec.class_path}[/dim]")
148
+
149
+ if init_kwargs:
150
+ merged_kwargs = {**policy_spec.init_kwargs, **init_kwargs}
151
+ policy_spec = PolicySpec(
152
+ class_path=policy_spec.class_path,
153
+ data_path=policy_spec.data_path,
154
+ init_kwargs=merged_kwargs,
155
+ )
156
+
157
+ if policy_spec.init_kwargs:
158
+ console.print(f"[dim]Init kwargs: {policy_spec.init_kwargs}[/dim]")
159
+
160
+ cwd = Path.cwd().resolve()
161
+ if policy_spec.data_path:
162
+ data_rel = str(_resolve_path_within_cwd(policy_spec.data_path, cwd))
163
+ policy_spec = PolicySpec(
164
+ class_path=policy_spec.class_path,
165
+ data_path=data_rel,
166
+ init_kwargs=policy_spec.init_kwargs,
167
+ )
168
+ console.print(f"[dim]Data path: {data_rel}[/dim]")
169
+
170
+ setup_script_rel: str | None = None
171
+ if setup_script:
172
+ setup_script_rel = str(_resolve_path_within_cwd(setup_script, cwd))
173
+ console.print(f"[dim]Setup script: {setup_script_rel}[/dim]")
174
+
175
+ files_to_include = []
176
+ if policy_spec.data_path:
177
+ files_to_include.append(policy_spec.data_path)
178
+ if setup_script_rel:
179
+ files_to_include.append(setup_script_rel)
180
+ if include_files:
181
+ files_to_include.extend(include_files)
182
+
183
+ validated_paths: list[Path] = []
184
+ if files_to_include:
185
+ validated_paths = validate_paths(files_to_include)
186
+ console.print(f"[dim]Including {len(validated_paths)} file(s)[/dim]")
187
+
188
+ tmp_zip = create_submission_zip(validated_paths, policy_spec, setup_script=setup_script_rel)
189
+ shutil.move(str(tmp_zip), str(output))
190
+ console.print(f"[dim]Bundle size: {output.stat().st_size / 1024:.0f} KB[/dim]")
191
+ return output
192
+
193
+
194
+ def validate_bundle(policy_uri: str, env_cfg: MettaGridConfig) -> None:
195
+ """Validate a policy bundle by running a short episode in process isolation."""
196
+ env_cfg.game.max_steps = 10
197
+
198
+ spec = EpisodeSpec(
199
+ policy_uris=[policy_uri],
200
+ assignments=[0] * env_cfg.game.num_agents,
201
+ env=env_cfg,
202
+ seed=42,
203
+ max_action_time_ms=10000,
204
+ )
205
+
206
+ with tempfile.NamedTemporaryFile(suffix=".json", delete=True) as results_file:
207
+ res = run_episode_isolated(spec, Path(results_file.name))
208
+ console.print(f"[dim]Ran for {res.steps} steps[/dim]")
209
+
210
+ non_noop_actions = sum(
211
+ v for k, v in res.stats["agent"][0].items() if k.startswith("action.") and ".noop." not in k
212
+ )
213
+ if non_noop_actions == 0:
214
+ console.print("[yellow]Warning: Policy took no actions (all no-ops)[/yellow]")
215
+ raise typer.Exit(1)
216
+
217
+
218
+ def upload_submission(
219
+ client: TournamentServerClient,
220
+ zip_path: Path,
221
+ submission_name: str,
222
+ season: str | None = None,
223
+ ) -> UploadResult | None:
224
+ """Upload submission to CoGames backend using a presigned S3 URL."""
225
+ console.print("[bold]Uploading[/bold]")
226
+
227
+ presigned_data = client.get_presigned_upload_url()
228
+ upload_url = presigned_data.get("upload_url")
229
+ upload_id = presigned_data.get("upload_id")
230
+
231
+ if not upload_url or not upload_id:
232
+ raise ValueError("Upload URL missing from response")
233
+
234
+ console.print("[dim]Uploading to storage...[/dim]")
235
+
236
+ with open(zip_path, "rb") as f:
237
+ upload_response = httpx.put(
238
+ upload_url,
239
+ content=f,
240
+ headers={"Content-Type": "application/zip"},
241
+ timeout=600.0,
242
+ )
243
+ upload_response.raise_for_status()
244
+
245
+ if not season:
246
+ console.print("[dim]Uploading policy...[/dim]")
247
+ else:
248
+ console.print(f"[dim]Uploading policy and submitting to season {season}...[/dim]")
249
+
250
+ result = client.complete_policy_upload(upload_id, submission_name, season=season)
251
+ submission_id = result.get("id")
252
+ name = result.get("name")
253
+ version = result.get("version")
254
+ pools = result.get("pools")
255
+ if submission_id is None or name is None or version is None:
256
+ raise ValueError("Missing fields in response")
257
+ try:
258
+ return UploadResult(
259
+ policy_version_id=uuid.UUID(str(submission_id)),
260
+ name=name,
261
+ version=version,
262
+ pools=pools,
263
+ )
264
+ except ValueError as exc:
265
+ raise ValueError(f"Invalid submission ID returned: {submission_id}") from exc
266
+
267
+
268
+ def upload_policy(
269
+ ctx: typer.Context,
270
+ policy: str,
271
+ name: str,
272
+ include_files: list[str] | None = None,
273
+ login_server: str = DEFAULT_COGAMES_SERVER,
274
+ server: str = DEFAULT_SUBMIT_SERVER,
275
+ init_kwargs: dict[str, str] | None = None,
276
+ dry_run: bool = False,
277
+ skip_validation: bool = False,
278
+ setup_script: str | None = None,
279
+ season: str | None = None,
280
+ ) -> UploadResult | None:
281
+ if dry_run:
282
+ console.print("[dim]Dry run mode - no upload[/dim]\n")
283
+
284
+ client = TournamentServerClient.from_login(server_url=server, login_server=login_server)
285
+ if not client:
286
+ return None
287
+
288
+ with tempfile.TemporaryDirectory(prefix="cogames_bundle_") as tmp_dir:
289
+ zip_path = Path(tmp_dir) / "bundle.zip"
290
+
291
+ create_bundle(
292
+ ctx=ctx,
293
+ policy=policy,
294
+ output=zip_path,
295
+ include_files=include_files,
296
+ init_kwargs=init_kwargs,
297
+ setup_script=setup_script,
298
+ )
299
+
300
+ if not skip_validation:
301
+ cmd = [
302
+ sys.executable,
303
+ "-m",
304
+ "cogames",
305
+ "validate-bundle",
306
+ "--policy",
307
+ zip_path.as_uri(),
308
+ "--server",
309
+ server,
310
+ ]
311
+ if season:
312
+ cmd.extend(["--season", season])
313
+ result = subprocess.run(cmd, text=True, timeout=300)
314
+ if result.returncode != 0:
315
+ console.print("[red]Validation failed[/red]")
316
+ return None
317
+ console.print("[green]Validation passed[/green]")
318
+ else:
319
+ console.print("[dim]Skipping validation[/dim]")
320
+
321
+ if dry_run:
322
+ console.print("[green]Dry run complete[/green]")
323
+ return None
324
+
325
+ with client:
326
+ result = upload_submission(client, zip_path, name, season=season)
327
+ if not result:
328
+ console.print("\n[red]Upload failed.[/red]")
329
+ return None
330
+
331
+ return result
@@ -63,7 +63,13 @@ from cogames.cli.policy import (
63
63
  policy_arg_example,
64
64
  policy_arg_w_proportion_example,
65
65
  )
66
- from cogames.cli.submit import DEFAULT_SUBMIT_SERVER, results_url_for_season, upload_policy, validate_policy_spec
66
+ from cogames.cli.submit import (
67
+ DEFAULT_SUBMIT_SERVER,
68
+ RESULTS_URL,
69
+ create_bundle,
70
+ upload_policy,
71
+ validate_bundle,
72
+ )
67
73
  from cogames.cogs_vs_clips.mission import CvCMission, NumCogsVariant
68
74
  from cogames.curricula import make_rotation
69
75
  from cogames.device import resolve_training_device
@@ -2228,12 +2234,12 @@ def _resolve_season(server: str, season_name: str | None = None) -> SeasonInfo:
2228
2234
 
2229
2235
 
2230
2236
  @app.command(
2231
- name="validate-policy",
2232
- help="Validate the policy loads and runs for at least a single step",
2237
+ name="create-bundle",
2238
+ help="Create a submission bundle zip from a policy",
2233
2239
  rich_help_panel="Policies",
2234
2240
  add_help_option=False,
2235
2241
  )
2236
- def validate_policy_cmd(
2242
+ def create_bundle_cmd(
2237
2243
  ctx: typer.Context,
2238
2244
  policy: str = typer.Option(
2239
2245
  ...,
@@ -2243,18 +2249,77 @@ def validate_policy_cmd(
2243
2249
  help=f"Policy specification: {policy_arg_example}",
2244
2250
  rich_help_panel="Policy",
2245
2251
  ),
2246
- device: str = typer.Option(
2247
- "auto",
2248
- "--device",
2249
- metavar="DEVICE",
2250
- help="Policy device (auto, cpu, cuda, cuda:0, etc.)",
2252
+ output: Path = typer.Option( # noqa: B008
2253
+ Path("submission.zip"),
2254
+ "--output",
2255
+ "-o",
2256
+ metavar="PATH",
2257
+ help="Output path for the bundle zip",
2258
+ rich_help_panel="Output",
2259
+ ),
2260
+ init_kwarg: Optional[list[str]] = typer.Option( # noqa: B008
2261
+ None,
2262
+ "--init-kwarg",
2263
+ "-k",
2264
+ metavar="KEY=VAL",
2265
+ help="Policy init kwargs (can be repeated)",
2251
2266
  rich_help_panel="Policy",
2252
2267
  ),
2268
+ include_files: Optional[list[str]] = typer.Option( # noqa: B008
2269
+ None,
2270
+ "--include-files",
2271
+ "-f",
2272
+ metavar="PATH",
2273
+ help="Files or directories to include (can be repeated)",
2274
+ rich_help_panel="Files",
2275
+ ),
2253
2276
  setup_script: Optional[str] = typer.Option(
2254
2277
  None,
2255
2278
  "--setup-script",
2256
- help="Path to a Python setup script to run before loading the policy",
2257
- rich_help_panel="Policy",
2279
+ metavar="PATH",
2280
+ help="Python setup script to include in the bundle",
2281
+ rich_help_panel="Files",
2282
+ ),
2283
+ _help: bool = typer.Option(
2284
+ False,
2285
+ "--help",
2286
+ "-h",
2287
+ help="Show this message and exit",
2288
+ is_eager=True,
2289
+ callback=_help_callback,
2290
+ rich_help_panel="Other",
2291
+ ),
2292
+ ) -> None:
2293
+ init_kwargs: dict[str, str] = {}
2294
+ if init_kwarg:
2295
+ for kv in init_kwarg:
2296
+ key, val = _parse_init_kwarg(kv)
2297
+ init_kwargs[key] = val
2298
+
2299
+ result_path = create_bundle(
2300
+ ctx=ctx,
2301
+ policy=policy,
2302
+ output=output.resolve(),
2303
+ include_files=include_files,
2304
+ init_kwargs=init_kwargs if init_kwargs else None,
2305
+ setup_script=setup_script,
2306
+ )
2307
+ console.print(f"[green]Bundle created:[/green] {result_path}")
2308
+
2309
+
2310
+ @app.command(
2311
+ name="validate-bundle",
2312
+ help="Validate a policy bundle runs correctly in process isolation",
2313
+ rich_help_panel="Policies",
2314
+ add_help_option=False,
2315
+ )
2316
+ def validate_bundle_cmd(
2317
+ policy: str = typer.Option(
2318
+ ...,
2319
+ "--policy",
2320
+ "-p",
2321
+ metavar="URI",
2322
+ help="Bundle URI (file://, s3://, or local path to .zip or directory)",
2258
2323
  ),
2259
2324
  season: Optional[str] = typer.Option(
2260
2325
  None,
@@ -2289,37 +2354,8 @@ def validate_policy_cmd(
2289
2354
  with TournamentServerClient(server_url=server) as client:
2290
2355
  config_data = client.get_config(entry_pool_info.config_id)
2291
2356
  env_cfg = MettaGridConfig.model_validate(config_data)
2357
+ validate_bundle(policy, env_cfg)
2292
2358
 
2293
- if setup_script:
2294
- import subprocess # noqa: PLC0415
2295
- import sys # noqa: PLC0415
2296
- from pathlib import Path # noqa: PLC0415
2297
-
2298
- script_path = Path(setup_script)
2299
- if not script_path.exists():
2300
- console.print(f"[red]Setup script not found: {setup_script}[/red]")
2301
- raise typer.Exit(1)
2302
- console.print(f"[yellow]Running setup script: {setup_script}[/yellow]")
2303
- result = subprocess.run(
2304
- [sys.executable, str(script_path)],
2305
- cwd=Path.cwd(),
2306
- capture_output=True,
2307
- text=True,
2308
- timeout=300,
2309
- )
2310
- if result.returncode != 0:
2311
- console.print(f"[red]Setup script failed:[/red]\n{result.stderr}")
2312
- raise typer.Exit(1)
2313
- console.print("[green]Setup script completed[/green]")
2314
-
2315
- resolved_device = resolve_training_device(console, device)
2316
- policy_spec = get_policy_spec(ctx, policy, device=str(resolved_device))
2317
- validate_policy_spec(
2318
- policy_spec,
2319
- env_cfg,
2320
- device=str(resolved_device),
2321
- season=season_info.name,
2322
- )
2323
2359
  console.print("[green]Policy validated successfully[/green]")
2324
2360
  raise typer.Exit(0)
2325
2361
 
@@ -2446,11 +2482,6 @@ def upload_cmd(
2446
2482
  ) -> None:
2447
2483
  season_info = _resolve_season(server, season)
2448
2484
 
2449
- has_entry_config = any(p.config_id for p in season_info.pools if p.name == season_info.entry_pool)
2450
- if not has_entry_config and not skip_validation:
2451
- console.print("[yellow]Warning: No entry config found for season. Skipping validation.[/yellow]")
2452
- skip_validation = True
2453
-
2454
2485
  init_kwargs: dict[str, str] = {}
2455
2486
  if init_kwarg:
2456
2487
  for kv in init_kwarg:
@@ -2468,7 +2499,6 @@ def upload_cmd(
2468
2499
  skip_validation=skip_validation,
2469
2500
  init_kwargs=init_kwargs if init_kwargs else None,
2470
2501
  setup_script=setup_script,
2471
- validation_season=season_info.name,
2472
2502
  season=season_info.name if not no_submit else None,
2473
2503
  )
2474
2504
 
@@ -2476,7 +2506,7 @@ def upload_cmd(
2476
2506
  console.print(f"[green]Upload complete: {result.name}:v{result.version}[/green]")
2477
2507
  if result.pools:
2478
2508
  console.print(f"[dim]Added to pools: {', '.join(result.pools)}[/dim]")
2479
- console.print(f"[dim]Results:[/dim] {results_url_for_season(server, season_info.name)}")
2509
+ console.print(f"[dim]Results:[/dim] {RESULTS_URL}")
2480
2510
  elif no_submit:
2481
2511
  console.print(f"\nTo submit to a tournament: cogames submit {result.name}:v{result.version}")
2482
2512
 
@@ -2574,7 +2604,7 @@ def submit_cmd(
2574
2604
  console.print(f"\n[bold green]Submitted to season '{season_name}'[/bold green]")
2575
2605
  if result.pools:
2576
2606
  console.print(f"[dim]Added to pools: {', '.join(result.pools)}[/dim]")
2577
- console.print(f"[dim]Results:[/dim] {results_url_for_season(server, season_name)}")
2607
+ console.print(f"[dim]Results:[/dim] {RESULTS_URL}")
2578
2608
  console.print(f"[dim]CLI:[/dim] cogames leaderboard --season {season_name}")
2579
2609
 
2580
2610
 
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cogames
3
- Version: 0.3.68
3
+ Version: 0.3.70
4
4
  Summary: Multi-agent cooperative games
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.12
7
7
  Requires-Python: <3.13,>=3.12
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
- Requires-Dist: mettagrid==0.2.0.82
10
+ Requires-Dist: mettagrid==0.2.0.84
11
11
  Requires-Dist: packaging>=24.0.0
12
12
  Requires-Dist: pufferlib-core
13
13
  Requires-Dist: pydantic>=2.11.5
@@ -1,4 +1,4 @@
1
- mettagrid==0.2.0.82
1
+ mettagrid==0.2.0.84
2
2
  packaging>=24.0.0
3
3
  pufferlib-core
4
4
  pydantic>=2.11.5