Skip to content

Commit a7d4e9f

Browse files
committed
Align Ruff config and enable docstring rules
1 parent e9d81ab commit a7d4e9f

52 files changed

Lines changed: 988 additions & 486 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

benchmark/atari_wrappers.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,34 @@ class NoopResetEnv(gym.Wrapper):
3333
"""
3434

3535
def __init__(self, env, noop_max=30):
36+
"""Initialize the no-op reset wrapper."""
3637
super().__init__(env)
3738
self.noop_max = noop_max
3839
self.noop_action = 0
3940
assert env.unwrapped.get_action_meanings()[0] == "NOOP"
4041

4142
def reset(self, *, seed=None, options=None):
43+
"""Reset the environment after a random number of no-op actions."""
4244
obs, info = self.env.reset(seed=seed, options=options)
4345
noops = self.unwrapped.np_random.integers(1, self.noop_max + 1)
4446
for _ in range(noops):
45-
obs, _, terminated, truncated, info = self.env.step(self.noop_action)
47+
obs, _, terminated, truncated, info = self.env.step(
48+
self.noop_action
49+
)
4650
if terminated or truncated:
4751
obs, info = self.env.reset()
4852
return obs, info
4953

5054

5155
class MaxAndSkipEnv(gym.Wrapper):
52-
"""Return only every `skip`-th frame (frameskipping) using most recent raw
53-
observations (for max pooling across time steps)
56+
"""Return every `skip`-th frame with max pooling over recent frames.
5457
5558
:param gym.Env env: the environment to wrap.
5659
:param int skip: number of `skip`-th frame.
5760
"""
5861

5962
def __init__(self, env, skip=4):
63+
"""Initialize the instance."""
6064
super().__init__(env)
6165
self._skip = skip
6266

@@ -85,11 +89,13 @@ class EpisodicLifeEnv(gym.Wrapper):
8589
"""
8690

8791
def __init__(self, env):
92+
"""Initialize episodic-life tracking."""
8893
super().__init__(env)
8994
self.lives = 0
9095
self.was_real_done = True
9196

9297
def step(self, action):
98+
"""Step the environment and treat life loss as episode end."""
9399
obs, reward, terminated, truncated, info = self.env.step(action)
94100
self.was_real_done = terminated or truncated
95101
# check current lives, make loss of life terminal, then update lives to
@@ -129,11 +135,13 @@ class FireResetEnv(gym.Wrapper):
129135
"""
130136

131137
def __init__(self, env):
138+
"""Initialize the fire-reset wrapper."""
132139
super().__init__(env)
133140
assert env.unwrapped.get_action_meanings()[1] == "FIRE"
134141
assert len(env.unwrapped.get_action_meanings()) >= 3
135142

136143
def reset(self, *, seed=None, options=None):
144+
"""Reset the environment and apply the fire action."""
137145
self.env.reset(seed=seed, options=options)
138146
obs, _, terminated, truncated, info = self.env.step(1)
139147
if terminated or truncated:
@@ -148,6 +156,7 @@ class WarpFrame(gym.ObservationWrapper):
148156
"""
149157

150158
def __init__(self, env):
159+
"""Initialize grayscale frame warping."""
151160
super().__init__(env)
152161
self.size = 84
153162
self.observation_space = gym.spaces.Box(
@@ -158,9 +167,11 @@ def __init__(self, env):
158167
)
159168

160169
def observation(self, frame):
161-
"""Returns the current observation from a frame"""
170+
"""Returns the current observation from a frame."""
162171
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
163-
return cv2.resize(frame, (self.size, self.size), interpolation=cv2.INTER_AREA)
172+
return cv2.resize(
173+
frame, (self.size, self.size), interpolation=cv2.INTER_AREA
174+
)
164175

165176

166177
class ScaledFloatFrame(gym.ObservationWrapper):
@@ -170,6 +181,7 @@ class ScaledFloatFrame(gym.ObservationWrapper):
170181
"""
171182

172183
def __init__(self, env):
184+
"""Initialize the instance."""
173185
super().__init__(env)
174186
low = np.min(env.observation_space.low)
175187
high = np.max(env.observation_space.high)
@@ -183,6 +195,7 @@ def __init__(self, env):
183195
)
184196

185197
def observation(self, observation):
198+
"""Scale an observation to the [0, 1] range."""
186199
return (observation - self.bias) / self.scale
187200

188201

@@ -193,6 +206,7 @@ class ClipRewardEnv(gym.RewardWrapper):
193206
"""
194207

195208
def __init__(self, env):
209+
"""Initialize reward clipping."""
196210
super().__init__(env)
197211
self.reward_range = (-1, 1)
198212

@@ -209,6 +223,7 @@ class FrameStack(gym.Wrapper):
209223
"""
210224

211225
def __init__(self, env, n_frames):
226+
"""Initialize the frame stack buffer."""
212227
super().__init__(env)
213228
self.n_frames = n_frames
214229
self.frames = deque([], maxlen=n_frames)
@@ -221,12 +236,14 @@ def __init__(self, env, n_frames):
221236
)
222237

223238
def reset(self, *, seed=None, options=None):
239+
"""Reset the environment and refill the frame stack."""
224240
obs, info = self.env.reset(seed=seed, options=options)
225241
for _ in range(self.n_frames):
226242
self.frames.append(obs)
227243
return self._get_ob(), info
228244

229245
def step(self, action):
246+
"""Step the environment and append the latest frame."""
230247
obs, reward, terminated, truncated, info = self.env.step(action)
231248
self.frames.append(obs)
232249
return self._get_ob(), reward, terminated, truncated, info

benchmark/plot.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16+
"""Plot benchmark results."""
17+
1618
import argparse
1719

1820
import matplotlib.ticker as ticker
@@ -23,6 +25,7 @@
2325

2426

2527
def reset_data() -> None:
28+
"""Reset the benchmark data accumulators."""
2629
global data
2730
data = {
2831
"Num. Workers": [],
@@ -34,6 +37,7 @@ def reset_data() -> None:
3437

3538

3639
def parse_table(env: str, system: str, suffix: str) -> None:
40+
"""Parse a benchmark table from a markdown report."""
3741
private_copy = {
3842
"Num. Workers": [],
3943
"FPS": [],
@@ -47,15 +51,17 @@ def parse_table(env: str, system: str, suffix: str) -> None:
4751
for line in raw[2:]:
4852
line = line.split("|")[1:-1]
4953
method = line.pop(0).strip()
50-
for w, f in zip(worker_num, line):
54+
for w, f in zip(worker_num, line, strict=False):
5155
for d in [data, private_copy]:
5256
d["Num. Workers"].append(w)
5357
d["FPS"].append(None if f.strip() == "/" else float(f))
5458
d["Env"].append(env)
5559
d["System"].append(system)
5660
d["Method"].append(method)
5761
d = pd.DataFrame(private_copy)
58-
plot = sns.lineplot(x="Num. Workers", y="FPS", hue="Method", data=d, marker="o")
62+
plot = sns.lineplot(
63+
x="Num. Workers", y="FPS", hue="Method", data=d, marker="o"
64+
)
5965
plot.xaxis.set_major_formatter(ticker.EngFormatter())
6066
plot.yaxis.set_major_formatter(ticker.EngFormatter())
6167
plot.legend(fontsize=9)
@@ -68,6 +74,7 @@ def parse_table(env: str, system: str, suffix: str) -> None:
6874

6975

7076
def benchmark(suffix: str) -> None:
77+
"""Generate throughput plots for benchmark results."""
7178
global data
7279
reset_data()
7380
for env in ["Atari", "Mujoco"]:
@@ -95,7 +102,7 @@ def mapping(x, y, **kwargs):
95102
g.add_legend(bbox_to_anchor=(0.52, 1.02), ncol=6)
96103
axes = g.axes.flatten()
97104
alphabet = "abcdefgh"
98-
for ax, i in zip(axes, alphabet):
105+
for ax, i in zip(axes, alphabet, strict=False):
99106
env, system = ax.get_title().split("|")
100107
env = env.split("=")[-1].strip()
101108
system = system.split("=")[-1].strip()

benchmark/test_dmc.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
"""Benchmark EnvPool against DeepMind Control."""
16+
1517
import argparse
1618
import time
1719

@@ -23,6 +25,7 @@
2325

2426

2527
def run_dmc(env, action, frame_skip, total_step):
28+
"""Benchmark a DeepMind Control environment."""
2629
ts = env.reset()
2730
t = time.time()
2831
for i in tqdm.trange(total_step):
@@ -36,6 +39,7 @@ def run_dmc(env, action, frame_skip, total_step):
3639

3740

3841
def run_envpool(env, action, frame_skip, total_step):
42+
"""Benchmark an EnvPool DeepMind Control environment."""
3943
ts = env.reset()
4044
t = time.time()
4145
for i in tqdm.trange(total_step):
@@ -61,9 +65,10 @@ def run_envpool(env, action, frame_skip, total_step):
6165
env = suite.load(args.domain, args.task, {"random": args.seed})
6266
np.random.seed(args.seed)
6367
minimum, maximum = env.action_spec().minimum, env.action_spec().maximum
64-
action = np.array(
65-
[np.random.uniform(low=minimum, high=maximum) for _ in range(args.total_step)]
66-
)
68+
action = np.array([
69+
np.random.uniform(low=minimum, high=maximum)
70+
for _ in range(args.total_step)
71+
])
6772
frame_skip = env._n_sub_steps
6873

6974
fps_dmc = run_dmc(env, action, frame_skip, args.total_step)

benchmark/test_envpool.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@
7272
if args.batch_size is None:
7373
args.batch_size = min(248, args.num_envs)
7474
elif args.batch_size > args.num_envs:
75-
raise ValueError("--batch-size must be less than or equal to --num-envs")
75+
raise ValueError(
76+
"--batch-size must be less than or equal to --num-envs"
77+
)
7678
print(args)
7779
task_id = {
7880
"atari": "Pong-v5",
@@ -91,7 +93,9 @@
9193
env = envpool.make_gym(task_id, **kwargs)
9294
env.async_reset()
9395
env.action_space.seed(args.seed)
94-
action = np.array([env.action_space.sample() for _ in range(args.batch_size)])
96+
action = np.array([
97+
env.action_space.sample() for _ in range(args.batch_size)
98+
])
9599
t = time.time()
96100
for _ in tqdm.trange(args.total_step):
97101
info = env.recv()[-1]

benchmark/test_gym.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
"""Benchmark EnvPool against Gym vector environments."""
16+
1517
import argparse
1618
import time
1719

@@ -22,6 +24,7 @@
2224

2325

2426
def make_vector_env(num_envs, async_, make_env):
27+
"""Create a Gym vector environment."""
2528
if async_:
2629
vector_env_cls = gym.vector.AsyncVectorEnv
2730
else:
@@ -30,6 +33,7 @@ def make_vector_env(num_envs, async_, make_env):
3033

3134

3235
def run(env, num_envs, total_step, async_):
36+
"""Benchmark a vectorized environment."""
3337
if env == "atari":
3438
gym.register_envs(ale_py)
3539
task_id = "ALE/Pong-v5"
@@ -88,7 +92,9 @@ def run(env, num_envs, total_step, async_):
8892

8993
if __name__ == "__main__":
9094
parser = argparse.ArgumentParser()
91-
parser.add_argument("--env", type=str, default="atari", choices=["atari", "mujoco", "box2d"])
95+
parser.add_argument(
96+
"--env", type=str, default="atari", choices=["atari", "mujoco", "box2d"]
97+
)
9298
parser.add_argument("--async_", action="store_true")
9399
parser.add_argument("--num-envs", type=int, default=10)
94100
parser.add_argument("--total-step", type=int, default=5000)

docs/conf.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
# list see the documentation:
55
# https://www.sphinx-doc.org/en/master/usage/configuration.html
66

7+
"""Sphinx configuration for the EnvPool docs."""
8+
79
# -- Path setup --------------------------------------------------------------
810

911
# If extensions (or modules to document with autodoc) are in another directory,
@@ -19,6 +21,7 @@
1921

2022
def get_version() -> str:
2123
# https://packaging.python.org/guides/single-sourcing-package-version/
24+
"""Return the project version from the package metadata."""
2225
with open(os.path.join("..", "envpool", "__init__.py"), "r") as f:
2326
init = f.read().split()
2427
return init[init.index("__version__") + 2][1:-1]
@@ -71,6 +74,7 @@ def get_version() -> str:
7174

7275

7376
def setup(app):
77+
"""Register the Sphinx configuration hooks."""
7478
app.add_js_file("js/copybutton.js")
7579
app.add_css_file("css/style.css")
7680

0 commit comments

Comments
 (0)