Skip to content

Commit b0e30da

Browse files
Gymlib + submodule infra (#58)
**Summary**: Set up submodules for agents and gymlib. **Demo**: The hello-tune agent ([repo@614687b](https://github.com/wangpatrick57/hello-tune/tree/614687b70ebd85be84b10de63e74e4813a36b30e)) calls `print(gymlib.magic.get_magic_number())` which successfully prints 42. <img width="759" alt="Screenshot 2024-12-25 at 15 17 50" src="https://github.com/user-attachments/assets/0d2bac20-1224-4ff2-93f0-7d8346e5413f" /> **Details**: * Each agent will be a git submodule inside `agents/`. * Each agent will have access to `gymlib/` as a Python library. * Each agent must use its own conda environment. You can use `.python_version` and `requirements.txt` inside the agent to define the env. This can be created automatically using `build_agent_conda_env.sh`. * The base gym will use the `dbgym` conda env. This can be created automatically using `build_gym_conda_env.sh`. * The current `tune/` folder is being deprecated and will be removed in a future PR. This is why the E2E tests are turned off in the CI.
1 parent 7a30af5 commit b0e30da

24 files changed

+165
-26
lines changed

.github/workflows/tests.yaml

+12-10
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ jobs:
3030
# We need to do `. "$HOME/.cargo/env"` in each step for it to work.
3131
- name: Install dependencies
3232
run: |
33-
./dependencies/install_dependencies.sh
33+
pip install -r ./scripts/configs/requirements.txt
34+
pip install -e ./gymlib
35+
./scripts/install_sysdeps.sh
3436
3537
- name: Check formatting
3638
run: |
@@ -57,12 +59,12 @@ jobs:
5759
export
5860
./scripts/run_integration_tests.sh
5961
60-
- name: Run end-to-end tests
61-
# End-to-end tests are like integration tests in that they require external systems to be running.
62-
# Unlike integration tests though, they don't perform detailed checks for any individual module.
63-
#
64-
# Note that we need to run with a non-root user in order to start Postgres. This is configured in the .yaml
65-
# file for our self-hosted GHA runners.
66-
run: |
67-
. "$HOME/.cargo/env"
68-
python -m scripts.run_protox_e2e_test ssd
62+
# - name: Run end-to-end tests
63+
# # End-to-end tests are like integration tests in that they require external systems to be running.
64+
# # Unlike integration tests though, they don't perform detailed checks for any individual module.
65+
# #
66+
# # Note that we need to run with a non-root user in order to start Postgres. This is configured in the .yaml
67+
# # file for our self-hosted GHA runners.
68+
# run: |
69+
# . "$HOME/.cargo/env"
70+
# python -m scripts.run_protox_e2e_test ssd

.gitignore

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ __pycache__/
33
.conda/
44
.idea/
55
test_clean_scratchspace/
6-
76
workspace/
8-
default_*_benchbase_config_*.xml
7+
default_*_benchbase_config_*.xml
8+
*.egg-info/

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "agents/hello-tune"]
2+
path = agents/hello-tune
3+
url = [email protected]:wangpatrick57/hello-tune.git

agents/hello-tune

Submodule hello-tune added at 614687b

dependencies/install_dependencies.sh

-5
This file was deleted.

gymlib/gymlib/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import magic

gymlib/gymlib/magic.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def get_magic_number() -> int:
2+
return 42

gymlib/pyproject.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "gymlib"
7+
version = "0.1.0"
8+
requires-python = ">=3.8"
9+
dependencies = []
10+
11+
[tool.setuptools]
12+
py-modules = ["gymlib"]

scripts/_build_conda_env.sh

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/bin/bash
2+
# This helper script creates a conda environment.
3+
# You should not run this directly. Instead, use build_agent_conda_env.sh or build_gym_conda_env.sh.
4+
5+
set -euo pipefail
6+
7+
# 1. Checks.
8+
# 1.1. Check that conda is installed.
9+
if ! command -v conda &> /dev/null; then
10+
echo "Error: Conda is not installed"
11+
exit 1
12+
fi
13+
14+
# 1.2. Input validation.
15+
if [ "$#" -lt 3 ]; then
16+
echo "Usage: ./_build_conda_env.sh <env_name> <python_version_path> <requirements_path>"
17+
exit 1
18+
fi
19+
20+
env_name=$1
21+
python_version_path=$2
22+
requirements_path=$3
23+
24+
# 1.3. Check that the environment doesn't already exist.
25+
if conda info --envs | grep -q "^$env_name "; then
26+
echo "Error: Conda environment '$env_name' already exists"
27+
exit 1
28+
fi
29+
30+
# 2. Set up the environment.
31+
# Note: I am intentionally not using environment.yml. I am instead using
32+
# requirements.txt and .python_version. This is for two reasons:
33+
# 1. environment.yml sets the conda env name. However, I want to enforce
34+
# that the conda env name is the same as the agent name.
35+
# 2. requirements.txt can be used by pip and only contains packages and
36+
# not any additional conda-specific syntax, making it more modular
37+
# and flexible.
38+
39+
# 2.1. Set python_version variable.
40+
if [ -f "$python_version_path" ]; then
41+
python_version=$(cat "$python_version_path")
42+
else
43+
echo "Warning: .python_version not found in $python_version_path. Using default Python 3.10."
44+
python_version="3.10"
45+
fi
46+
47+
# 2.2. Create conda environment with specified Python version.
48+
echo "Creating conda environment '$env_name' with Python $python_version..."
49+
eval "$(conda shell.bash hook)"
50+
conda create -y -n "$env_name" python="$python_version"
51+
52+
# 2.3. Install the packages.
53+
conda activate "$env_name"
54+
55+
if [ -f "$requirements_path" ]; then
56+
echo "Installing pip requirements from $requirements_path..."
57+
pip install -r "$requirements_path"
58+
else
59+
echo "Warning: $requirements_path not found. Skipping pip install."
60+
fi
61+
62+
# We always install gymlib so that the agent has access to it.
63+
if [ -d "gymlib" ]; then
64+
echo "Installing gymlib in editable mode..."
65+
pip install -e ./gymlib
66+
else
67+
echo "Error: gymlib directory not found in $(pwd). Please ensure you're running this script from the right folder."
68+
exit 1
69+
fi
70+
71+
conda deactivate
72+
73+
# 2.4. Success message.
74+
echo "Conda environment '$env_name' created successfully."
75+
echo "It is not currently activated. To activate it, run 'conda activate $env_name'."
File renamed without changes.

scripts/build_agent_conda_env.sh

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/bash
2+
# This script creates a conda environment for a specific agent.
3+
# - Name matches the agent name.
4+
# - Python version from .python_version file in the agent's folder (if exists).
5+
# - Dependencies from requirements.txt file in the agent's folder (if exists).
6+
# - gymlib is installed.
7+
#
8+
# Using this script is *optional*. If you have a more complex environment setup
9+
# for your agent, just do that manually.
10+
#
11+
# Run it from the dbgym root folder (e.g. `./scripts/build_agent_conda_env.sh <agent_name>`).
12+
#
13+
# Before running this script, the user must update the folder of the agent
14+
# they want to create a conda environment for (e.g. by calling submodule update).
15+
# There are other things the user must do as well but these are all checked
16+
# automatically by this script.
17+
18+
set -euo pipefail
19+
20+
if [ -z "$1" ]; then
21+
echo "Usage: ./build_agent_conda_env.sh <agent_name>"
22+
exit 1
23+
fi
24+
25+
agent_name=$1
26+
27+
if [ ! -d "agents/$agent_name" ]; then
28+
echo "Error: Agent folder '$agent_name' does not exist"
29+
exit 1
30+
fi
31+
32+
./scripts/_build_conda_env.sh "$agent_name" "agents/$agent_name/.python_version" "agents/$agent_name/requirements.txt"

scripts/build_dbgym_conda_env.sh

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
# This script builds the conda environment used by the gym itself (i.e. the orchestrator).
3+
# This script is optional. You don't need to use conda if you don't want to (the CI doesn't use conda, for instance)
4+
5+
set -euo pipefail
6+
7+
./scripts/_build_conda_env.sh "dbgym" "scripts/configs/.python_version" "scripts/configs/requirements.txt"

scripts/check_format.sh

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/bin/bash
22
set -euxo pipefail
33

4-
black . --check
5-
isort . --profile black -c
4+
# Ignore agents/ because those are all submodules.
5+
black . --check --exclude agents
6+
isort . --profile black -c --skip agents

scripts/configs/.python_version

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.10.13
File renamed without changes.
File renamed without changes.

scripts/format.sh

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/bin/bash
2-
set -euxo pipefail
2+
set -euo pipefail
33

4-
black .
5-
isort . --profile black
4+
# Ignore agents/ because those are all submodules.
5+
black . --exclude agents
6+
isort . --profile black --skip agents

scripts/install_sysdeps.sh

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
# "sysdeps" stands for "system dependencies".
3+
# These are dependencies unrelated to Python that the dbgym needs.
4+
cat scripts/configs/apt_requirements.txt | xargs sudo apt-get install -y
5+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

scripts/mypy.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
#!/bin/bash
2-
mypy --config-file scripts/mypy.ini .
2+
# Ignore agents/ because those are all submodules.
3+
mypy --config-file scripts/configs/mypy.ini . --exclude agents/

scripts/run_integration_tests.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/bin/bash
2-
python -m scripts.run_tests "integtest_*.py"
2+
python -m scripts._run_tests "integtest_*.py"

scripts/run_protox_e2e_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
# Be careful when changing these constants. In some places, the E2E test is hardcoded to work for these specific constants.
2727
DBMS = "postgres"
2828
AGENT = "protox"
29-
E2ETEST_DBGYM_CONFIG_FPATH = Path("scripts/e2e_test_dbgym_config.yaml")
29+
E2ETEST_DBGYM_CONFIG_FPATH = Path("scripts/configs/e2e_test_dbgym_config.yaml")
3030

3131

3232
def get_workspace_dpath(config_fpath: Path) -> Path:

scripts/run_unit_tests.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/bin/bash
2-
python -m scripts.run_tests "unittest_*.py"
2+
python -m scripts._run_tests "unittest_*.py"

0 commit comments

Comments
 (0)