Skip to content

Commit 662b610

Browse files
committed
Feat: Specify output dir/suffix
1 parent 3d5fb0f commit 662b610

5 files changed

Lines changed: 74 additions & 9 deletions

File tree

codeclash/tournaments/pvp.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import json
66
from concurrent.futures import ThreadPoolExecutor
7+
from pathlib import Path
78

89
from codeclash.agents import get_agent
910
from codeclash.agents.player import Player
@@ -16,8 +17,8 @@
1617

1718

1819
class PvpTournament(AbstractTournament):
19-
def __init__(self, config: dict, *, cleanup: bool = False, push: bool = False):
20-
super().__init__(config, name="PvpTournament")
20+
def __init__(self, config: dict, *, cleanup: bool = False, push: bool = False, output_dir: Path | None = None):
21+
super().__init__(config, name="PvpTournament", output_dir=output_dir)
2122
self.cleanup_on_end = cleanup
2223
self.game: CodeGame = get_game(
2324
self.config,

codeclash/tournaments/single_player.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import copy
66
import json
7+
from pathlib import Path
78

89
from codeclash.agents import get_agent
910
from codeclash.agents.dummy_agent import Dummy
@@ -18,8 +19,8 @@
1819

1920

2021
class SinglePlayerTraining(AbstractTournament):
21-
def __init__(self, config: dict, *, cleanup: bool = False):
22-
super().__init__(config, name="SinglePlayerTraining")
22+
def __init__(self, config: dict, *, cleanup: bool = False, output_dir: Path | None = None):
23+
super().__init__(config, name="SinglePlayerTraining", output_dir=output_dir)
2324
self.cleanup_on_end = cleanup
2425
self.game: CodeGame = get_game(
2526
self.config,

codeclash/tournaments/tournament.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010

1111

1212
class AbstractTournament:
13-
def __init__(self, config: dict, *, name: str, **kwargs):
13+
def __init__(self, config: dict, *, name: str, output_dir: Path | None = None, **kwargs):
1414
self.config: dict = config
1515
self.name: str = name
1616
self.tournament_id: str = f"{self.name}.{config['game']['name']}.{time.strftime('%y%m%d%H%M%S')}"
17+
self._custom_output_dir: Path | None = output_dir
1718
self._metadata: dict = {
1819
"name": self.name,
1920
"tournament_id": self.tournament_id,
@@ -24,6 +25,11 @@ def __init__(self, config: dict, *, name: str, **kwargs):
2425

2526
@property
2627
def local_output_dir(self) -> Path:
28+
if self._custom_output_dir is not None:
29+
# Custom output directory provided, add timestamp to make it unique
30+
return (self._custom_output_dir / time.strftime("%y%m%d%H%M%S")).resolve()
31+
32+
# Default behavior
2733
base_dir = DIR_LOGS
2834
if "PYTEST_CURRENT_TEST" in os.environ:
2935
base_dir = Path("/tmp/codeclash")

main.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
11
import argparse
2+
import getpass
23
from pathlib import Path
34

45
import yaml
56

67
from codeclash import CONFIG_DIR
8+
from codeclash.constants import DIR_LOGS
79
from codeclash.tournaments.pvp import PvpTournament
810
from codeclash.utils.yaml_utils import resolve_includes
911

1012

11-
def main(config_path: Path, *, cleanup: bool = False, push: bool = False):
13+
def main(
14+
config_path: Path,
15+
*,
16+
cleanup: bool = False,
17+
push: bool = False,
18+
output_dir: Path | None = None,
19+
suffix: str = "",
20+
):
1221
yaml_content = config_path.read_text()
1322
preprocessed_yaml = resolve_includes(yaml_content, base_dir=CONFIG_DIR)
1423
config = yaml.safe_load(preprocessed_yaml)
15-
tournament = PvpTournament(config, cleanup=cleanup, push=push)
24+
25+
folder_name = f"PvpTournament.{config['game']['name']}{suffix}"
26+
if output_dir is None:
27+
full_output_dir = DIR_LOGS / getpass.getuser() / folder_name
28+
else:
29+
full_output_dir = output_dir / folder_name
30+
31+
tournament = PvpTournament(config, cleanup=cleanup, push=push, output_dir=full_output_dir)
1632
tournament.run()
1733

1834

@@ -35,6 +51,19 @@ def main_cli(argv: list[str] | None = None):
3551
action="store_true",
3652
help="If set, push each agent's codebase to a new repository after running.",
3753
)
54+
parser.add_argument(
55+
"-o",
56+
"--output-dir",
57+
type=Path,
58+
help="Sets the output directory (default is 'logs' with current user subdirectory).",
59+
)
60+
parser.add_argument(
61+
"-s",
62+
"--suffix",
63+
type=str,
64+
help="Suffix to attach to the folder name. Does not include leading dot or underscore.",
65+
default="",
66+
)
3867
args = parser.parse_args(argv)
3968
main(**vars(args))
4069

main_single_player.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
import argparse
2+
import getpass
23
from pathlib import Path
34

45
import yaml
56

67
from codeclash import CONFIG_DIR
8+
from codeclash.constants import DIR_LOGS
79
from codeclash.tournaments.single_player import SinglePlayerTraining
810
from codeclash.utils.yaml_utils import resolve_includes
911

1012

11-
def main(config_path: Path, cleanup: bool = False):
13+
def main(
14+
config_path: Path,
15+
*,
16+
cleanup: bool = False,
17+
output_dir: Path | None = None,
18+
suffix: str = "",
19+
):
1220
yaml_content = config_path.read_text()
1321
preprocessed_yaml = resolve_includes(yaml_content, base_dir=CONFIG_DIR)
1422
config = yaml.safe_load(preprocessed_yaml)
15-
training = SinglePlayerTraining(config, cleanup=cleanup)
23+
24+
folder_name = f"SinglePlayerTraining.{config['game']['name']}{suffix}"
25+
if output_dir is None:
26+
full_output_dir = DIR_LOGS / getpass.getuser() / folder_name
27+
else:
28+
full_output_dir = output_dir / folder_name
29+
30+
training = SinglePlayerTraining(config, cleanup=cleanup, output_dir=full_output_dir)
1631
training.run()
1732

1833

@@ -29,6 +44,19 @@ def main_cli(argv: list[str] | None = None):
2944
action="store_true",
3045
help="If set, do not clean up the game environment after running.",
3146
)
47+
parser.add_argument(
48+
"-o",
49+
"--output-dir",
50+
type=Path,
51+
help="Sets the output directory (default is 'logs' with current user subdirectory).",
52+
)
53+
parser.add_argument(
54+
"-s",
55+
"--suffix",
56+
type=str,
57+
help="Suffix to attach to the folder name. Does not include leading dot or underscore.",
58+
default="",
59+
)
3260
args = parser.parse_args(argv)
3361
main(**vars(args))
3462

0 commit comments

Comments
 (0)