Skip to content

Commit 7ebe8ae

Browse files
zuorenchenchichunwangthc1006
authored
Release v0.0.2 (#33)
* Fix evaluate's encode problem (#5) * Fix evaluate's encode problem * Update yaml encoding * Update to return reward from each step only. Total count of popped balloon is returned in info. #10 (#12) * DOC: readme (#11) * MNT: README * MNT: fix scenario 0 balloon position info. #8 * Skip Monte Carlo balloon simulation for scenario 0 (#18) * Skip Monte Carlo balloon simulation for scenario 0 scenario 0 uses static balloons at fixed heights, but reset() ran a full Monte Carlo balloon-flight simulation every call and immediately overwrote the result with static positions. Move the Monte Carlo path into the non-scenario-0 branch and build the static balloon array directly via a new __generate_static_balloon_flights helper. The resulting _balloon_flights array is identical to before; only the wasted Monte Carlo run and its file writes are removed. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Add pytest to dev optional-dependencies The scenario 0 test suite lives in tests/; declare pytest in the dev extra so it installs via requirements-dev.txt and the suite can be run. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --------- Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Make vpython an optional, lazily-imported render dependency (#15) vpython was imported at module scope in balloon_world.py and listed as a hard dependency, so importing the environment required vpython even for matplotlib rendering or render_mode=None (e.g. Colab). Move the import into the vpython branch of _render_frame and expose vpython via a `vpython` optional extra. Default installs and the matplotlib renderer are unaffected; `pip install -e ".[vpython]"` enables it. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Clean up dead code, redundant calls, and unused imports (#7) * Add cleanup invariant tests AST-based static checks for redundant file.close() after with-open, dead class-level imports, drifted example agent_kwargs, and empty f-strings. No new dependencies beyond the standard library and PyYAML. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Remove dead code, redundant calls, and unused imports - evaluate.py: drop three redundant file.close() after with-open - example_agents.py: drop dead class-level get_initial_attitude import inside NavigationAgent (already imported at module scope) - balloon_world.py: drop unused rocketpy.Function and vpython.arrow imports; drop f-prefix from two f-strings without interpolation - example_eval_cfg.yaml: drop dummy arg3 unused by AttitudeRateControlAgent - envs/__init__.py: use explicit "as" re-export to satisfy F401 Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Document how to run tests and ignore .ci-venv Add a Testing section to README pointing at "python -m unittest discover tests", and gitignore the throwaway venv name commonly used to install ruff locally. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Declare PyYAML as a dependency evaluate.py and the cleanup tests import yaml, but PyYAML was never declared in pyproject.toml dependencies and is not pulled in transitively. A fresh `pip install -r requirements.txt` therefore leaves `import yaml` failing with ModuleNotFoundError. Add pyyaml to the project dependencies. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --------- Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> Co-authored-by: ZuoRen Chen <180084773+zuorenchen@users.noreply.github.com> * Move Monte Carlo output out of the package directory (#22) * Move Monte Carlo output out of the package directory __generate_balloon_flights passed MonteCarlo a filename inside the installed package directory (BalloonPoppingGymEnv/envs/data/), so every non-scenario-0 reset wrote balloon_sim.{inputs,outputs,errors}.txt there. That fails in read-only / installed environments and pollutes the package tree. Write to tempfile.gettempdir() instead; the env only uses the in-memory simulate() results, so the persisted files are a pure side effect whose location does not affect behavior. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Use a per-process Monte Carlo output filename tempfile.gettempdir() is shared across OS users, so a fixed "balloon_sim" name there can collide: on a shared host the second user's reset() hits a PermissionError writing the first user's files. Suffix the name with the process id so concurrent processes and users get distinct paths. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --------- Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Add uv as the recommended environment setup path (#20) * Add uv as the recommended environment setup path uv installs the pinned Python, creates the virtual environment, and installs locked dependencies in one step, lowering the setup barrier for contributors. Declare activerocketpy as a path dependency via [tool.uv.sources] so uv resolves the submodule, pin Python to 3.14 via .python-version, and commit uv.lock. The requirements.txt / pip path is unchanged and still works for users who do not use uv. Also drop the duplicate vpython entry left in [project.dependencies] by the PR #7 / #15 merge -- vpython is the optional extra only. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Switch the README uv setup to the standalone installer The uv steps said `pip install uv` then `uv sync`, but pip places the uv executable in a scripts directory that is frequently not on PATH, so the bare `uv` command then fails. Document uv's standalone installer instead, which puts `uv` on PATH, and add a troubleshooting note covering a stale shell, PATH, and the `python -m uv` fallback. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --------- Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Add standardized issue templates (#25) Add GitHub issue form templates under .github/ISSUE_TEMPLATE: a bug report, a feature request / proposal, and a question form, plus a config that keeps blank issues enabled. Each form collects the context that otherwise has to be asked for in follow-up comments. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * ENH: Add architecture for post sim graphics (#28) * Enhance BalloonPoppingEnv with trajectory logging and tidy up attribute in _init_ and reset * Add save_trajectory function to save balloon and rocket trajectories into json file. Call save_trajectories in evaluate_scenario. TODO: render_trajectory * ENH: Add leaderboard submission functions (#31) * Enhance BalloonPoppingEnv with trajectory logging and tidy up attribute in _init_ and reset * Add save_trajectory function to save balloon and rocket trajectories into json file. Call save_trajectories in evaluate_scenario. TODO: render_trajectory * Add balloon_status to trajectories * ENH: pack results for leaderboard submission * Add time to trajectory log * Save trajectory file in UTC * Add gust to balloon_world environment (#32) * Add gust model configuration to environment parameters and implement gust handling in BalloonPoppingEnv (cherry picked from commit 9550377) * Refactor quasi-random gust model * Fix rng usage. run __create_environment() after env.reset --------- Co-authored-by: RickyRicato <rickywang44@gmail.com> * Render every balloon in the vpython renderer (#27) * Render every balloon in the vpython renderer _render_frame's vpython branch created a single sphere and positioned it from _balloon_states[0], so a scenario with N balloons showed only the first. Create one sphere per balloon and update them all, which matches the matplotlib branch that already slices over every balloon. Add tests/test_render.py, which mocks vpython and checks that a reset creates one sphere per balloon. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Assert the vpython renderer repositions every balloon The render test checked that num spheres are created but not that all of them are repositioned each frame, so a regression updating only one sphere would still pass. Add a vector() call-count assertion that pins the per-balloon update loop. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * ENH: Add rocket and balloon colors to vpython rendering * Add vPython option to comment --------- Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> Co-authored-by: zuorenchen <zuorenchen@m110.nthu.edu.tw> * Add GitHub Actions CI workflow (#23) * Add GitHub Actions CI workflow Set up .github/workflows/ci.yml with a lint job (ruff check and format check) and a test job that installs the project with its ActiveRocketPy submodule, runs the suite with coverage, and uploads a coverage report. CI runs on pushes to main, pull requests, and manual dispatch. The Codecov upload step stays dormant until a CODECOV_TOKEN secret is configured. Add tests/test_import_smoke.py to confirm the package and example agents import after an install, and declare pytest-cov as a dev dependency for coverage generation. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Bump CI actions off the deprecated Node 20 runtime actions/checkout@v4, actions/setup-python@v5 and actions/upload-artifact@v4 run on Node 20, which GitHub deprecates in June 2026. Move them to the current majors (v6, v6, v7), which run on Node 24. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Probe the simulation stack with find_spec in the smoke test The skip guard used importlib.import_module, which executes rocketpy and so cannot tell an installed-but-broken stack apart from an absent one -- test_import_example_agents would skip the import breakage it exists to catch. find_spec checks installation without importing, so the test runs and fails loudly when an installed stack is broken. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --------- Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> * Update readme (#34) * Add leaderboard information * Run formatter * Add release notes * Update release notes --------- Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> Co-authored-by: ChiChun Wang <99960850+chichunwang@users.noreply.github.com> Co-authored-by: 秀吉 <84045975+thc1006@users.noreply.github.com> Co-authored-by: RickyRicato <rickywang44@gmail.com>
1 parent 3aaf775 commit 7ebe8ae

27 files changed

Lines changed: 5951 additions & 107 deletions
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Bug report
2+
description: Report something broken in the simulator, environment, or evaluation
3+
title: "[Bug] "
4+
labels: ["bug"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
Thanks for reporting a bug. Please give enough detail for it to be reproduced.
10+
- type: textarea
11+
id: summary
12+
attributes:
13+
label: What happened
14+
description: A clear description of the bug, and what you expected instead.
15+
validations:
16+
required: true
17+
- type: textarea
18+
id: repro
19+
attributes:
20+
label: Steps to reproduce
21+
description: Commands, scenario number, agent, and config used. A minimal snippet helps.
22+
placeholder: |
23+
1. ...
24+
2. ...
25+
validations:
26+
required: true
27+
- type: textarea
28+
id: logs
29+
attributes:
30+
label: Error output / traceback
31+
description: Paste the full traceback or log. It is formatted as code automatically.
32+
render: shell
33+
validations:
34+
required: false
35+
- type: input
36+
id: environment
37+
attributes:
38+
label: Environment
39+
description: OS, Python version, install method (uv / pip), and the commit or branch.
40+
placeholder: "Windows 11, Python 3.14, uv, develop @ abc1234"
41+
validations:
42+
required: true

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
blank_issues_enabled: true
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Feature request / proposal
2+
description: Propose an enhancement, a design change, or new functionality
3+
title: "[Proposal] "
4+
labels: ["enhancement"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
Use this for enhancements and design discussions. For a non-trivial change, open the proposal here and discuss before sending a PR.
10+
- type: textarea
11+
id: problem
12+
attributes:
13+
label: Problem / current state
14+
description: What is missing or not working well today, and why it matters.
15+
validations:
16+
required: true
17+
- type: textarea
18+
id: proposal
19+
attributes:
20+
label: Proposed change
21+
description: What you want to do. Outline the approach and the files or areas affected.
22+
validations:
23+
required: true
24+
- type: textarea
25+
id: alternatives
26+
attributes:
27+
label: Alternatives and trade-offs
28+
description: Other options considered, and the trade-offs of the proposed one.
29+
validations:
30+
required: false
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Question
2+
description: Ask about using the simulator, the competition, or the leaderboard
3+
title: "[Question] "
4+
labels: ["question"]
5+
body:
6+
- type: textarea
7+
id: question
8+
attributes:
9+
label: Your question
10+
description: What you are trying to do, and what you are unsure about.
11+
validations:
12+
required: true
13+
- type: textarea
14+
id: context
15+
attributes:
16+
label: Context
17+
description: What you have already tried, the relevant scenario or config, and docs you have already read.
18+
validations:
19+
required: false

.github/workflows/ci.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
workflow_dispatch:
8+
9+
concurrency:
10+
group: ci-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
lint:
15+
name: Lint and format
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Check out repository
19+
uses: actions/checkout@v6
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v6
23+
with:
24+
python-version: "3.14"
25+
26+
- name: Install ruff
27+
run: python -m pip install ruff
28+
29+
- name: Lint
30+
run: ruff check BalloonPoppingGymEnv/ tests/
31+
32+
- name: Format check
33+
run: ruff format --check BalloonPoppingGymEnv/ tests/
34+
35+
test:
36+
name: Tests and coverage
37+
runs-on: ubuntu-latest
38+
env:
39+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
40+
steps:
41+
- name: Check out repository
42+
uses: actions/checkout@v6
43+
with:
44+
submodules: recursive
45+
46+
- name: Set up Python
47+
uses: actions/setup-python@v6
48+
with:
49+
python-version: "3.14"
50+
cache: pip
51+
cache-dependency-path: requirements-dev.txt
52+
53+
- name: Install dependencies
54+
run: |
55+
python -m pip install --upgrade pip
56+
pip install -r requirements-dev.txt
57+
58+
- name: Run tests with coverage
59+
run: pytest tests/ --cov=BalloonPoppingGymEnv --cov-report=xml --cov-report=term
60+
61+
- name: Upload coverage artifact
62+
if: ${{ !cancelled() }}
63+
uses: actions/upload-artifact@v7
64+
with:
65+
name: coverage-xml
66+
path: coverage.xml
67+
if-no-files-found: warn
68+
69+
# Skipped until a CODECOV_TOKEN repository secret is configured.
70+
- name: Upload coverage to Codecov
71+
if: ${{ env.CODECOV_TOKEN != '' }}
72+
uses: codecov/codecov-action@v5
73+
with:
74+
token: ${{ secrets.CODECOV_TOKEN }}
75+
files: coverage.xml
76+
fail_ci_if_error: false

.gitignore

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ BalloonPoppingGymEnv/envs/data/*
33
!BalloonPoppingGymEnv/envs/data/**.md
44
!BalloonPoppingGymEnv/envs/data/**.nc
55

6+
BalloonPoppingGymEnv/evaluation/results/**.json
7+
BalloonPoppingGymEnv/evaluation/results/**.pkl
8+
69
# VSCode specific
710
.vscode/
811

912
# Python specific
1013
.venv
14+
.ci-venv
1115
.ruff_cache
12-
__pycache__
16+
__pycache__
17+
.pytest_cache
18+
.coverage
19+
coverage.xml

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.14

BalloonPoppingGymEnv/agents/example_agents.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ def get_action(self, observation):
109109
class NavigationAgent(BaseAgent):
110110
"""A simple inertial navigation agent that integrates rocket states"""
111111

112-
from BalloonPoppingGymEnv.envs.balloon_world import get_initial_attitude
113-
114112
def __init__(self, *args, **kwargs):
115113
super().__init__(*args)
116114

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
from BalloonPoppingGymEnv.envs.balloon_world import BalloonPoppingEnv
1+
from BalloonPoppingGymEnv.envs.balloon_world import (
2+
BalloonPoppingEnv as BalloonPoppingEnv,
3+
)

0 commit comments

Comments
 (0)