mirror of
https://github.com/saymrwulf/stable-baselines3.git
synced 2026-09-17 22:30:59 +00:00
Add flake8 linter and Github CI (#19)
* Cleanup code * Add flake8 lint and github workflow * Update build matrix * Relax precision for python3.7
This commit is contained in:
parent
299c28140e
commit
54f6f5b6fb
17 changed files with 130 additions and 45 deletions
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
|
@ -24,6 +24,7 @@
|
||||||
- [ ] My change requires a change to the documentation.
|
- [ ] My change requires a change to the documentation.
|
||||||
- [ ] I have updated the tests accordingly (*required for a bug fix or a new feature*).
|
- [ ] I have updated the tests accordingly (*required for a bug fix or a new feature*).
|
||||||
- [ ] I have updated the documentation accordingly.
|
- [ ] I have updated the documentation accordingly.
|
||||||
- [ ] I have ensured `pytest` and `pytype` both pass.
|
- [ ] I have checked the codestyle using `make lint`
|
||||||
|
- [ ] I have ensured `make pytest` and `make type` both pass.
|
||||||
|
|
||||||
<!--- This Template is an edited version of the one from https://github.com/evilsocket/pwnagotchi/ -->
|
<!--- This Template is an edited version of the one from https://github.com/evilsocket/pwnagotchi/ -->
|
||||||
|
|
|
||||||
43
.github/workflows/ci.yml
vendored
Normal file
43
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
|
||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||||
|
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
# Skip CI if [ci skip] in the commit message
|
||||||
|
if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: [3.6, 3.7] # 3.8 not supported yet by pytype
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
# cpu version of pytorch
|
||||||
|
pip install torch==1.4.0+cpu -f https://download.pytorch.org/whl/torch_stable.html
|
||||||
|
pip install .[extra,tests,docs]
|
||||||
|
# Use headless version
|
||||||
|
pip install opencv-python-headless
|
||||||
|
- name: Type check
|
||||||
|
run: |
|
||||||
|
make type
|
||||||
|
- name: Lint with flake8
|
||||||
|
run: |
|
||||||
|
make lint
|
||||||
|
- name: Test with pytest
|
||||||
|
run: |
|
||||||
|
make pytest
|
||||||
|
|
@ -99,6 +99,12 @@ Type checking with `pytype`:
|
||||||
make type
|
make type
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Codestyle check with `flake8`:
|
||||||
|
|
||||||
|
```
|
||||||
|
make lint
|
||||||
|
```
|
||||||
|
|
||||||
Build the documentation:
|
Build the documentation:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
9
Makefile
9
Makefile
|
|
@ -6,6 +6,13 @@ pytest:
|
||||||
type:
|
type:
|
||||||
pytype
|
pytype
|
||||||
|
|
||||||
|
lint:
|
||||||
|
# stop the build if there are Python syntax errors or undefined names
|
||||||
|
# see https://lintlyci.github.io/Flake8Rules/
|
||||||
|
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||||
|
# exit-zero treats all errors as warnings.
|
||||||
|
flake8 . --count --exit-zero --statistics
|
||||||
|
|
||||||
doc:
|
doc:
|
||||||
cd docs && make html
|
cd docs && make html
|
||||||
|
|
||||||
|
|
@ -15,7 +22,7 @@ spelling:
|
||||||
clean:
|
clean:
|
||||||
cd docs && make clean
|
cd docs && make clean
|
||||||
|
|
||||||
.PHONY: clean spelling doc
|
.PHONY: clean spelling doc lint
|
||||||
|
|
||||||
# Build docker images
|
# Build docker images
|
||||||
# If you do export RELEASE=True, it will also push them
|
# If you do export RELEASE=True, it will also push them
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ Others:
|
||||||
- Sync ``VecEnvs`` with Stable-Baselines
|
- Sync ``VecEnvs`` with Stable-Baselines
|
||||||
- Update requirement: ``gym>=0.17``
|
- Update requirement: ``gym>=0.17``
|
||||||
- Added ``.readthedoc.yml`` file
|
- Added ``.readthedoc.yml`` file
|
||||||
|
- Added ``flake8`` and ``make lint`` command
|
||||||
|
- Added Github workflow
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
27
setup.cfg
27
setup.cfg
|
|
@ -19,3 +19,30 @@ filterwarnings =
|
||||||
|
|
||||||
[pytype]
|
[pytype]
|
||||||
inputs = stable_baselines3
|
inputs = stable_baselines3
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
ignore = W503,W504 # line breaks before and after binary operators
|
||||||
|
# Ignore import not used when aliases are defined
|
||||||
|
per-file-ignores =
|
||||||
|
./stable_baselines3/__init__.py:F401
|
||||||
|
./stable_baselines3/common/__init__.py:F401
|
||||||
|
./stable_baselines3/a2c/__init__.py:F401
|
||||||
|
./stable_baselines3/ppo/__init__.py:F401
|
||||||
|
./stable_baselines3/sac/__init__.py:F401
|
||||||
|
./stable_baselines3/td3/__init__.py:F401
|
||||||
|
./stable_baselines3/common/vec_env/__init__.py:F401
|
||||||
|
exclude =
|
||||||
|
# No need to traverse our git directory
|
||||||
|
.git,
|
||||||
|
# There's no value in checking cache directories
|
||||||
|
__pycache__,
|
||||||
|
# Don't check the doc
|
||||||
|
docs/
|
||||||
|
# This contains our built documentation
|
||||||
|
build,
|
||||||
|
# This contains builds of flake8 that we don't want to check
|
||||||
|
dist
|
||||||
|
*.egg-info
|
||||||
|
max-complexity = 15
|
||||||
|
# The GitHub editor is 127 chars wide
|
||||||
|
max-line-length = 127
|
||||||
|
|
|
||||||
54
setup.py
54
setup.py
|
|
@ -1,6 +1,4 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
with open(os.path.join('stable_baselines3', 'version.txt'), 'r') as file_handler:
|
with open(os.path.join('stable_baselines3', 'version.txt'), 'r') as file_handler:
|
||||||
|
|
@ -63,14 +61,14 @@ from stable_baselines3 import PPO
|
||||||
model = PPO('MlpPolicy', 'CartPole-v1').learn(10000)
|
model = PPO('MlpPolicy', 'CartPole-v1').learn(10000)
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
""" # noqa:E501
|
||||||
|
|
||||||
|
|
||||||
setup(name='stable_baselines3',
|
setup(name='stable_baselines3',
|
||||||
packages=[package for package in find_packages()
|
packages=[package for package in find_packages()
|
||||||
if package.startswith('stable_baselines3')],
|
if package.startswith('stable_baselines3')],
|
||||||
package_data={
|
package_data={
|
||||||
'stable_baselines3': ['py.typed', 'version.txt']
|
'stable_baselines3': ['py.typed', 'version.txt']
|
||||||
},
|
},
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'gym>=0.17',
|
'gym>=0.17',
|
||||||
|
|
@ -84,28 +82,32 @@ setup(name='stable_baselines3',
|
||||||
'matplotlib'
|
'matplotlib'
|
||||||
],
|
],
|
||||||
extras_require={
|
extras_require={
|
||||||
'tests': [
|
'tests': [
|
||||||
'pytest',
|
# Run tests and coverage
|
||||||
'pytest-cov',
|
'pytest',
|
||||||
'pytest-env',
|
'pytest-cov',
|
||||||
'pytest-xdist',
|
'pytest-env',
|
||||||
'pytype',
|
'pytest-xdist',
|
||||||
],
|
# Type check
|
||||||
'docs': [
|
'pytype',
|
||||||
'sphinx',
|
# Lint code
|
||||||
'sphinx-autobuild',
|
'flake8>=3.8'
|
||||||
'sphinx-rtd-theme',
|
],
|
||||||
# For spelling
|
'docs': [
|
||||||
'sphinxcontrib.spelling',
|
'sphinx',
|
||||||
# Type hints support
|
'sphinx-autobuild',
|
||||||
# 'sphinx-autodoc-typehints'
|
'sphinx-rtd-theme',
|
||||||
],
|
# For spelling
|
||||||
'extra': [
|
'sphinxcontrib.spelling',
|
||||||
# For render
|
# Type hints support
|
||||||
'opencv-python',
|
# 'sphinx-autodoc-typehints'
|
||||||
# For atari games,
|
],
|
||||||
'atari_py~=0.2.0', 'pillow'
|
'extra': [
|
||||||
]
|
# For render
|
||||||
|
'opencv-python',
|
||||||
|
# For atari games,
|
||||||
|
'atari_py~=0.2.0', 'pillow'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
description='Pytorch version of Stable Baselines, implementations of reinforcement learning algorithms.',
|
description='Pytorch version of Stable Baselines, implementations of reinforcement learning algorithms.',
|
||||||
author='Antonin Raffin',
|
author='Antonin Raffin',
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ from typing import Dict, Any, Optional, Callable, Type, Union
|
||||||
|
|
||||||
import gym
|
import gym
|
||||||
|
|
||||||
from stable_baselines3.common import logger
|
|
||||||
from stable_baselines3.common.monitor import Monitor
|
from stable_baselines3.common.monitor import Monitor
|
||||||
from stable_baselines3.common.utils import set_random_seed
|
|
||||||
from stable_baselines3.common.atari_wrappers import AtariWrapper
|
from stable_baselines3.common.atari_wrappers import AtariWrapper
|
||||||
from stable_baselines3.common.vec_env import DummyVecEnv, SubprocVecEnv
|
from stable_baselines3.common.vec_env import DummyVecEnv, SubprocVecEnv
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import List, Union, Optional
|
from typing import Union, Optional
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from gym import Env, Space
|
from gym import Env, Space
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,8 @@ class OrnsteinUhlenbeckActionNoise(ActionNoise):
|
||||||
super(OrnsteinUhlenbeckActionNoise, self).__init__()
|
super(OrnsteinUhlenbeckActionNoise, self).__init__()
|
||||||
|
|
||||||
def __call__(self) -> np.ndarray:
|
def __call__(self) -> np.ndarray:
|
||||||
noise = self.noise_prev + self._theta * (self._mu - self.noise_prev) * self._dt + \
|
noise = (self.noise_prev + self._theta * (self._mu - self.noise_prev) * self._dt
|
||||||
self._sigma * np.sqrt(self._dt) * np.random.normal(size=self._mu.shape)
|
+ self._sigma * np.sqrt(self._dt) * np.random.normal(size=self._mu.shape))
|
||||||
self.noise_prev = noise
|
self.noise_prev = noise
|
||||||
return noise
|
return noise
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from stable_baselines3.common.vec_env.base_vec_env import VecEnv, VecEnvWrapper
|
||||||
from stable_baselines3.common.preprocessing import is_image_space
|
from stable_baselines3.common.preprocessing import is_image_space
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from stable_baselines3.common.type_aliases import GymStepReturn
|
from stable_baselines3.common.type_aliases import GymStepReturn # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
class VecTransposeImage(VecEnvWrapper):
|
class VecTransposeImage(VecEnvWrapper):
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ def test_squashed_gaussian(model_class):
|
||||||
actions = dist.get_actions()
|
actions = dist.get_actions()
|
||||||
assert th.max(th.abs(actions)) <= 1.0
|
assert th.max(th.abs(actions)) <= 1.0
|
||||||
|
|
||||||
|
|
||||||
def test_sde_distribution():
|
def test_sde_distribution():
|
||||||
n_actions = 1
|
n_actions = 1
|
||||||
deterministic_actions = th.ones(N_SAMPLES, n_actions) * 0.1
|
deterministic_actions = th.ones(N_SAMPLES, n_actions) * 0.1
|
||||||
|
|
@ -95,4 +96,4 @@ def test_categorical():
|
||||||
actions = dist.get_actions()
|
actions = dist.get_actions()
|
||||||
entropy = dist.entropy()
|
entropy = dist.entropy()
|
||||||
log_prob = dist.log_prob(actions)
|
log_prob = dist.log_prob(actions)
|
||||||
assert th.allclose(entropy.mean(), -log_prob.mean(), rtol=1e-4)
|
assert th.allclose(entropy.mean(), -log_prob.mean(), rtol=2e-4)
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ def test_high_dimension_action_space():
|
||||||
env = FakeImageEnv()
|
env = FakeImageEnv()
|
||||||
# Patch the action space
|
# Patch the action space
|
||||||
env.action_space = spaces.Box(low=-1, high=1, shape=(20,), dtype=np.float32)
|
env.action_space = spaces.Box(low=-1, high=1, shape=(20,), dtype=np.float32)
|
||||||
|
|
||||||
# Patch to avoid error
|
# Patch to avoid error
|
||||||
def patched_step(_action):
|
def patched_step(_action):
|
||||||
return env.observation_space.sample(), 0.0, False, {}
|
return env.observation_space.sample(), 0.0, False, {}
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,6 @@ def test_save_load_policy(model_class, policy_str):
|
||||||
|
|
||||||
del policy, actor
|
del policy, actor
|
||||||
|
|
||||||
|
|
||||||
policy = policy_class.load("./logs/policy.pkl")
|
policy = policy_class.load("./logs/policy.pkl")
|
||||||
if actor_class is not None:
|
if actor_class is not None:
|
||||||
actor = actor_class.load("./logs/actor.pkl")
|
actor = actor_class.load("./logs/actor.pkl")
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ def test_make_vec_env(env_id, n_envs, vec_env_cls, wrapper_class):
|
||||||
@pytest.mark.parametrize("env_id", ['BreakoutNoFrameskip-v4'])
|
@pytest.mark.parametrize("env_id", ['BreakoutNoFrameskip-v4'])
|
||||||
@pytest.mark.parametrize("n_envs", [1, 2])
|
@pytest.mark.parametrize("n_envs", [1, 2])
|
||||||
@pytest.mark.parametrize("wrapper_kwargs", [None, dict(clip_reward=False, screen_size=60)])
|
@pytest.mark.parametrize("wrapper_kwargs", [None, dict(clip_reward=False, screen_size=60)])
|
||||||
def test_make_vec_env(env_id, n_envs, wrapper_kwargs):
|
def test_make_atari_env(env_id, n_envs, wrapper_kwargs):
|
||||||
env_id = 'BreakoutNoFrameskip-v4'
|
env_id = 'BreakoutNoFrameskip-v4'
|
||||||
env = make_atari_env(env_id, n_envs,
|
env = make_atari_env(env_id, n_envs,
|
||||||
wrapper_kwargs=wrapper_kwargs, monitor_dir=None, seed=0)
|
wrapper_kwargs=wrapper_kwargs, monitor_dir=None, seed=0)
|
||||||
|
|
@ -55,15 +55,14 @@ def test_make_vec_env(env_id, n_envs, wrapper_kwargs):
|
||||||
if wrapper_kwargs is not None:
|
if wrapper_kwargs is not None:
|
||||||
assert obs.shape == (n_envs, 60, 60, 1)
|
assert obs.shape == (n_envs, 60, 60, 1)
|
||||||
assert wrapped_atari_env.observation_space.shape == (60, 60, 1)
|
assert wrapped_atari_env.observation_space.shape == (60, 60, 1)
|
||||||
assert wrapped_atari_env.clip_reward == False
|
assert wrapped_atari_env.clip_reward is False
|
||||||
else:
|
else:
|
||||||
assert obs.shape == (n_envs, 84, 84, 1)
|
assert obs.shape == (n_envs, 84, 84, 1)
|
||||||
assert wrapped_atari_env.observation_space.shape == (84, 84, 1)
|
assert wrapped_atari_env.observation_space.shape == (84, 84, 1)
|
||||||
assert wrapped_atari_env.clip_reward == True
|
assert wrapped_atari_env.clip_reward is True
|
||||||
assert np.max(np.abs(reward)) < 1.0
|
assert np.max(np.abs(reward)) < 1.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_custom_vec_env(tmp_path):
|
def test_custom_vec_env(tmp_path):
|
||||||
"""
|
"""
|
||||||
Stand alone test for a special case (passing a custom VecEnv class) to avoid doubling the number of tests.
|
Stand alone test for a special case (passing a custom VecEnv class) to avoid doubling the number of tests.
|
||||||
|
|
@ -73,7 +72,6 @@ def test_custom_vec_env(tmp_path):
|
||||||
monitor_dir=monitor_dir, seed=0,
|
monitor_dir=monitor_dir, seed=0,
|
||||||
vec_env_cls=SubprocVecEnv, vec_env_kwargs={'start_method': None})
|
vec_env_cls=SubprocVecEnv, vec_env_kwargs={'start_method': None})
|
||||||
|
|
||||||
|
|
||||||
assert env.num_envs == 1
|
assert env.num_envs == 1
|
||||||
assert isinstance(env, SubprocVecEnv)
|
assert isinstance(env, SubprocVecEnv)
|
||||||
assert os.path.isdir(monitor_dir)
|
assert os.path.isdir(monitor_dir)
|
||||||
|
|
|
||||||
|
|
@ -68,5 +68,4 @@ def test_check_nan():
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
env.step(np.array([[0, 1], [0, 1]]))
|
env.step(np.array([[0, 1], [0, 1]]))
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ import pytest
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from stable_baselines3.common.running_mean_std import RunningMeanStd
|
from stable_baselines3.common.running_mean_std import RunningMeanStd
|
||||||
from stable_baselines3.common.vec_env import DummyVecEnv, VecNormalize, VecFrameStack, sync_envs_normalization, unwrap_vec_normalize
|
from stable_baselines3.common.vec_env import (DummyVecEnv, VecNormalize, VecFrameStack, sync_envs_normalization,
|
||||||
|
unwrap_vec_normalize)
|
||||||
from stable_baselines3 import SAC, TD3
|
from stable_baselines3 import SAC, TD3
|
||||||
|
|
||||||
ENV_ID = 'Pendulum-v0'
|
ENV_ID = 'Pendulum-v0'
|
||||||
|
|
@ -53,8 +54,8 @@ def _make_warmstart_cartpole():
|
||||||
def test_runningmeanstd():
|
def test_runningmeanstd():
|
||||||
"""Test RunningMeanStd object"""
|
"""Test RunningMeanStd object"""
|
||||||
for (x_1, x_2, x_3) in [
|
for (x_1, x_2, x_3) in [
|
||||||
(np.random.randn(3), np.random.randn(4), np.random.randn(5)),
|
(np.random.randn(3), np.random.randn(4), np.random.randn(5)),
|
||||||
(np.random.randn(3, 2), np.random.randn(4, 2), np.random.randn(5, 2))]:
|
(np.random.randn(3, 2), np.random.randn(4, 2), np.random.randn(5, 2))]:
|
||||||
rms = RunningMeanStd(epsilon=0.0, shape=x_1.shape[1:])
|
rms = RunningMeanStd(epsilon=0.0, shape=x_1.shape[1:])
|
||||||
|
|
||||||
x_cat = np.concatenate([x_1, x_2, x_3], axis=0)
|
x_cat = np.concatenate([x_1, x_2, x_3], axis=0)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue