diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c5d88ac82..82385e14b 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ +--- github: Farama-Foundation diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 223b02dce..03d4b311a 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -1,51 +1,52 @@ +--- name: Bug Report description: Submit a bug report -title: "[Bug Report] Bug title" -labels: ["bug"] +title: '[Bug Report] Bug title' +labels: [bug] body: - - type: textarea - id: description - attributes: - label: Describe the bug - description: A clear and concise description of what the bug is. - validations: - required: true + - type: textarea + id: description + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. + validations: + required: true - - type: textarea - id: code-example - attributes: - label: Code example - description: | - Bug reports without minimal code examples take 5-10x longer to solve. - We'll give you a cookie if you add the stack trace too! - Save time, add code. - This will be automatically formatted into code, so no need for backticks. - render: shell + - type: textarea + id: code-example + attributes: + label: Code example + description: | + Bug reports without minimal code examples take 5-10x longer to solve. + We'll give you a cookie if you add the stack trace too! + Save time, add code. + This will be automatically formatted into code, so no need for backticks. + render: shell - - type: textarea - id: system-info - attributes: - label: System info - description: | - Describe the characteristic of your environment: - * Describe how PettingZoo was installed (pip, source, ...) - * Version of `pettingzoo` (by `pettingzoo.__version__`) - * What OS/version you're using. Note that while we will accept PRs to improve Window's support, we do not officially support it. - * Python version + - type: textarea + id: system-info + attributes: + label: System info + description: | + Describe the characteristic of your environment: + * Describe how PettingZoo was installed (pip, source, ...) + * Version of `pettingzoo` (by `pettingzoo.__version__`) + * What OS/version you're using. Note that while we will accept PRs to improve Window's support, we do not officially support it. + * Python version - - type: textarea - id: additional-context - attributes: - label: Additional context - description: Add any other context about the problem here. + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Add any other context about the problem here. - - type: checkboxes - id: checklist - attributes: - label: Checklist - options: - - label: > - I have checked that there is no similar [issue](https://github.com/Farama-Foundation/PettingZoo/issues) in - the repo - required: true + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: > + I have checked that there is no similar [issue](https://github.com/Farama-Foundation/PettingZoo/issues) in + the repo + required: true diff --git a/.github/ISSUE_TEMPLATE/proposal.yml b/.github/ISSUE_TEMPLATE/proposal.yml index f485b628c..848877c36 100644 --- a/.github/ISSUE_TEMPLATE/proposal.yml +++ b/.github/ISSUE_TEMPLATE/proposal.yml @@ -1,49 +1,50 @@ +--- name: Proposal description: Propose changes that are not fixing bugs -title: "[Proposal] Proposal title" -labels: ["enhancement"] +title: '[Proposal] Proposal title' +labels: [enhancement] body: - - type: textarea - id: proposal - attributes: - label: Proposal - description: A clear and concise description of the proposal. - validations: - required: true + - type: textarea + id: proposal + attributes: + label: Proposal + description: A clear and concise description of the proposal. + validations: + required: true - - type: textarea - id: motivation - attributes: - label: Motivation - description: | - Please outline the motivation for the proposal. - Is your feature request related to a problem? e.g.,"I'm always frustrated when [...]". - If this is related to another GitHub issue, please link here too. + - type: textarea + id: motivation + attributes: + label: Motivation + description: | + Please outline the motivation for the proposal. + Is your feature request related to a problem? e.g.,"I'm always frustrated when [...]". + If this is related to another GitHub issue, please link here too. - - type: textarea - id: pitch - attributes: - label: Pitch - description: A clear and concise description of what you want to happen. + - type: textarea + id: pitch + attributes: + label: Pitch + description: A clear and concise description of what you want to happen. - - type: textarea - id: alternatives - attributes: - label: Alternatives - description: A clear and concise description of any alternative solutions or features you've considered, if any. + - type: textarea + id: alternatives + attributes: + label: Alternatives + description: A clear and concise description of any alternative solutions or features you've considered, if any. - - type: textarea - id: additional-context - attributes: - label: Additional context - description: Add any other context or screenshots about the feature request here. + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. - - type: checkboxes - id: checklist - attributes: - label: Checklist - options: - - label: > - I have checked that there is no similar [issue](https://github.com/Farama-Foundation/PettingZoo/issues) in - the repo - required: true + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: > + I have checked that there is no similar [issue](https://github.com/Farama-Foundation/PettingZoo/issues) in + the repo + required: true diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index 94c7feeee..8af14d3de 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -1,22 +1,23 @@ +--- name: Question description: Ask a question -title: "[Question] Question title" -labels: ["question"] +title: '[Question] Question title' +labels: [question] body: - - type: markdown - attributes: - value: > - If you have basic questions about reinforcement learning algorithms, please ask on - [r/reinforcementlearning](https://www.reddit.com/r/reinforcementlearning/) or in the - [RL Discord](https://discord.com/invite/xhfNqQv) (if you're new please use the beginners channel). - Basic questions that are not bugs or feature requests will be closed without reply, because GitHub - issues are not an appropriate venue for these. Advanced/nontrivial questions, especially in areas where - documentation is lacking, are very much welcome. + - type: markdown + attributes: + value: > + If you have basic questions about reinforcement learning algorithms, please ask on + [r/reinforcementlearning](https://www.reddit.com/r/reinforcementlearning/) or in the + [RL Discord](https://discord.com/invite/xhfNqQv) (if you're new please use the beginners channel). + Basic questions that are not bugs or feature requests will be closed without reply, because GitHub + issues are not an appropriate venue for these. Advanced/nontrivial questions, especially in areas where + documentation is lacking, are very much welcome. - - type: textarea - id: question - attributes: - label: Question - description: Your question - validations: - required: true + - type: textarea + id: question + attributes: + label: Question + description: Your question + validations: + required: true diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index af0d78329..bc8367dcd 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -1,49 +1,50 @@ +--- name: Build Documentation website on: - push: - branches: [master] + push: + branches: [master] permissions: - contents: write + contents: write jobs: - docs: - name: Generate Website - runs-on: ubuntu-latest - env: - SPHINX_GITHUB_CHANGELOG_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v3 + docs: + name: Generate Website + runs-on: ubuntu-latest + env: + SPHINX_GITHUB_CHANGELOG_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.9' + - uses: actions/setup-python@v4 + with: + python-version: '3.9' - - name: Install dependencies - run: pip install -r docs/requirements.txt + - name: Install dependencies + run: pip install -r docs/requirements.txt - - name: Install PettingZoo - run: pip install .[all] + - name: Install PettingZoo + run: pip install .[all] - - name: Generate environment docs - run: python docs/_scripts/gen_envs_mds.py + - name: Generate environment docs + run: python docs/_scripts/gen_envs_mds.py - - name: Generate environments display - run: python docs/_scripts/gen_envs_display.py + - name: Generate environments display + run: python docs/_scripts/gen_envs_display.py - - name: Build - run: sphinx-build -b dirhtml -v docs _build + - name: Build + run: sphinx-build -b dirhtml -v docs _build - - name: Move 404 - run: mv _build/404/index.html _build/404.html + - name: Move 404 + run: mv _build/404/index.html _build/404.html - - name: Update 404 links - run: python docs/_scripts/move_404.py _build/404.html + - name: Update 404 links + run: python docs/_scripts/move_404.py _build/404.html - - name: Remove .doctrees - run: rm -r _build/.doctrees + - name: Remove .doctrees + run: rm -r _build/.doctrees - - name: Upload to GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4 - with: - folder: _build - target-folder: main - clean: false + - name: Upload to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: _build + target-folder: main + clean: false diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 799fda065..d52c6a3ef 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -1,3 +1,4 @@ +--- # This workflow will build and (if release) publish Python distributions to PyPI # For more information see: # - https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions @@ -7,57 +8,57 @@ name: build-publish on: - release: - types: [published] + release: + types: [published] jobs: - build-wheels: - runs-on: ${{ matrix.os }} - permissions: - contents: read - strategy: - matrix: - include: - - os: ubuntu-latest - python: 38 - platform: manylinux_x86_64 - - os: ubuntu-latest - python: 39 - platform: manylinux_x86_64 - - os: ubuntu-latest - python: 310 - platform: manylinux_x86_64 - - os: ubuntu-latest - python: 311 - platform: manylinux_x86_64 + build-wheels: + runs-on: ${{ matrix.os }} + permissions: + contents: read + strategy: + matrix: + include: + - os: ubuntu-latest + python: 38 + platform: manylinux_x86_64 + - os: ubuntu-latest + python: 39 + platform: manylinux_x86_64 + - os: ubuntu-latest + python: 310 + platform: manylinux_x86_64 + - os: ubuntu-latest + python: 311 + platform: manylinux_x86_64 - steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - name: Install dependencies - run: python -m pip install --upgrade setuptools wheel build - - name: Build wheels - run: python -m build --sdist --wheel - - name: Store wheels - uses: actions/upload-artifact@v2 - with: - path: dist + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + - name: Install dependencies + run: python -m pip install --upgrade setuptools wheel build + - name: Build wheels + run: python -m build --sdist --wheel + - name: Store wheels + uses: actions/upload-artifact@v2 + with: + path: dist - publish: - runs-on: ubuntu-latest - needs: - - build-wheels - if: github.event_name == 'release' && github.event.action == 'published' - steps: - - name: Download dists - uses: actions/download-artifact@v2 - with: - name: artifact - path: dist - - name: Publish - uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} + publish: + runs-on: ubuntu-latest + needs: + - build-wheels + if: github.event_name == 'release' && github.event.action == 'published' + steps: + - name: Download dists + uses: actions/download-artifact@v2 + with: + name: artifact + path: dist + - name: Publish + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/docs-manual-versioning.yml b/.github/workflows/docs-manual-versioning.yml index 4c2688419..bde319b3f 100644 --- a/.github/workflows/docs-manual-versioning.yml +++ b/.github/workflows/docs-manual-versioning.yml @@ -1,74 +1,75 @@ +--- name: Manual Docs Versioning on: - workflow_dispatch: - inputs: - version: - description: 'Documentation version to create' - required: true - commit: - description: 'Commit used to build the Documentation version' - required: false - latest: - description: 'Latest version' - type: boolean + workflow_dispatch: + inputs: + version: + description: Documentation version to create + required: true + commit: + description: Commit used to build the Documentation version + required: false + latest: + description: Latest version + type: boolean permissions: - contents: write + contents: write jobs: - docs: - name: Generate Website for new version - runs-on: ubuntu-latest - env: - SPHINX_GITHUB_CHANGELOG_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v3 - if: inputs.commit == '' + docs: + name: Generate Website for new version + runs-on: ubuntu-latest + env: + SPHINX_GITHUB_CHANGELOG_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 + if: inputs.commit == '' - - uses: actions/checkout@v3 - if: inputs.commit != '' - with: - ref: ${{ inputs.commit }} + - uses: actions/checkout@v3 + if: inputs.commit != '' + with: + ref: ${{ inputs.commit }} - - uses: actions/setup-python@v4 - with: - python-version: '3.9' + - uses: actions/setup-python@v4 + with: + python-version: '3.9' - - name: Install dependencies - run: pip install -r docs/requirements.txt + - name: Install dependencies + run: pip install -r docs/requirements.txt - - name: Install PettingZoo - run: pip install .[all] + - name: Install PettingZoo + run: pip install .[all] - - name: Generate environment docs - run: python docs/_scripts/gen_envs_mds.py + - name: Generate environment docs + run: python docs/_scripts/gen_envs_mds.py - - name: Generate environments display - run: python docs/_scripts/gen_envs_display.py + - name: Generate environments display + run: python docs/_scripts/gen_envs_display.py - - name: Build - run: sphinx-build -b dirhtml -v docs _build + - name: Build + run: sphinx-build -b dirhtml -v docs _build - - name: Move 404 - run: mv _build/404/index.html _build/404.html + - name: Move 404 + run: mv _build/404/index.html _build/404.html - - name: Update 404 links - run: python docs/_scripts/move_404.py _build/404.html + - name: Update 404 links + run: python docs/_scripts/move_404.py _build/404.html - - name: Remove .doctrees - run: rm -r _build/.doctrees + - name: Remove .doctrees + run: rm -r _build/.doctrees - - name: Upload to GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4 - with: - folder: _build - target-folder: ${{ inputs.version }} - clean: false + - name: Upload to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: _build + target-folder: ${{ inputs.version }} + clean: false - - name: Upload to GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4 - if: inputs.latest - with: - folder: _build - clean-exclude: | - *.*.*/ - main + - name: Upload to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + if: inputs.latest + with: + folder: _build + clean-exclude: | + *.*.*/ + main diff --git a/.github/workflows/docs-test.yml b/.github/workflows/docs-test.yml new file mode 100644 index 000000000..d916fa8b0 --- /dev/null +++ b/.github/workflows/docs-test.yml @@ -0,0 +1,67 @@ +--- +name: Documentation tests + +on: + push: + branches: [master] + pull_request: + branches: [master] + +permissions: + contents: read + +jobs: + docs-test: + runs-on: ubuntu-latest + strategy: + matrix: + group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3.11 + uses: actions/setup-python@v3 + with: + python-version: '3.11' + - name: Install dependencies + run: | + sudo apt-get install python3-opengl xvfb + pip install -e .[all] + pip install -e .[testing] + pip install supersuit shimmy pytest-split + AutoROM -v + - name: Install documentation dependencies + run: pip install -r docs/requirements.txt + - name: Generate environment docs + run: python docs/_scripts/gen_envs_mds.py + - name: Download durations from most recent GitHub workflow run + id: download-artifact + uses: dawidd6/action-download-artifact@v2 + with: + if_no_artifact_found: warn + - name: Documentation test + run: | + xvfb-run -s "-screen 0 1024x768x24" pytest docs --markdown-docs -m markdown-docs --splits 10 --group ${{ matrix.group }} --store-durations --clean-durations + - name: Upload partial durations + uses: actions/upload-artifact@v3 + with: + name: split-${{ matrix.group }} + path: .test_durations + upload-timings: + needs: docs-test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Download artifacts + uses: actions/download-artifact@v3 + - name: Combine test-durations + run: | + # Move all test durations to same folder and append numbers + find . -type f -name '.test_durations' -exec bash -c 'i=1; while [ -e "./test_durations_$i" ]; do i=$((i+1)); done; mv "$1" "./test_durations_$i";' _ {} \; + # Combine all test durations files + jq -s 'reduce inputs as $item ({}; . + $item)' .test_durations.* > .test_durations + continue-on-error: true + - name: Upload final durations + uses: actions/upload-artifact@v3 + with: + name: split-${{ matrix.group }} + path: .test_durations diff --git a/.github/workflows/docs-versioning.yml b/.github/workflows/docs-versioning.yml index e892a1d91..eb6905c4c 100644 --- a/.github/workflows/docs-versioning.yml +++ b/.github/workflows/docs-versioning.yml @@ -1,64 +1,65 @@ +--- name: Docs Versioning on: - push: - tags: - - 'v?*.*.*' + push: + tags: + - v?*.*.* permissions: - contents: write + contents: write jobs: - docs: - name: Generate Website for new version - runs-on: ubuntu-latest - env: - SPHINX_GITHUB_CHANGELOG_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v3 + docs: + name: Generate Website for new version + runs-on: ubuntu-latest + env: + SPHINX_GITHUB_CHANGELOG_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.9' + - uses: actions/setup-python@v4 + with: + python-version: '3.9' - - name: Get tag - id: tag - uses: dawidd6/action-get-tag@v1 - with: - strip_v: true + - name: Get tag + id: tag + uses: dawidd6/action-get-tag@v1 + with: + strip_v: true - - name: Install dependencies - run: pip install -r docs/requirements.txt + - name: Install dependencies + run: pip install -r docs/requirements.txt - - name: Install PettingZoo - run: pip install .[all] + - name: Install PettingZoo + run: pip install .[all] - - name: Generate environment docs - run: python docs/_scripts/gen_envs_mds.py + - name: Generate environment docs + run: python docs/_scripts/gen_envs_mds.py - - name: Generate environments display - run: python docs/_scripts/gen_envs_display.py + - name: Generate environments display + run: python docs/_scripts/gen_envs_display.py - - name: Build - run: sphinx-build -b dirhtml -v docs _build + - name: Build + run: sphinx-build -b dirhtml -v docs _build - - name: Move 404 - run: mv _build/404/index.html _build/404.html + - name: Move 404 + run: mv _build/404/index.html _build/404.html - - name: Update 404 links - run: python docs/_scripts/move_404.py _build/404.html + - name: Update 404 links + run: python docs/_scripts/move_404.py _build/404.html - - name: Remove .doctrees - run: rm -r _build/.doctrees + - name: Remove .doctrees + run: rm -r _build/.doctrees - - name: Upload to GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4 - with: - folder: _build - target-folder: ${{steps.tag.outputs.tag}} - clean: false + - name: Upload to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: _build + target-folder: ${{steps.tag.outputs.tag}} + clean: false - - name: Upload to GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4 - with: - folder: _build - clean-exclude: | - *.*.*/ - main + - name: Upload to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: _build + clean-exclude: | + *.*.*/ + main diff --git a/.github/workflows/linux-test.yml b/.github/workflows/linux-test.yml index 30cdbe6b8..2d25a5dde 100644 --- a/.github/workflows/linux-test.yml +++ b/.github/workflows/linux-test.yml @@ -1,41 +1,38 @@ -# 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: Python tests on: - push: - branches: [master] - pull_request: - branches: [master] + push: + branches: [master] + pull_request: + branches: [master] permissions: - contents: read + contents: read jobs: - linux-test: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] - steps: - - uses: actions/checkout@v3 - # - uses: openrndr/setup-opengl@v1.1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - sudo apt-get install python3-opengl xvfb - pip install -e .[all] - pip install -e .[testing] - AutoROM -v - - name: Source distribution test - run: | - python -m pip install --upgrade build - python -m build --sdist - pip install dist/*.tar.gz - - name: Release Test - run: | - xvfb-run -s "-screen 0 1024x768x24" pytest -v --cov=pettingzoo --cov-report term + linux-test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11'] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + sudo apt-get install python3-opengl xvfb + pip install -e .[all] + pip install -e .[testing] + AutoROM -v + - name: Source distribution test + run: | + python -m pip install --upgrade build + python -m build --sdist + pip install dist/*.tar.gz + - name: Release Test + run: | + xvfb-run -s "-screen 0 1024x768x24" pytest -v --cov=pettingzoo --cov-report term diff --git a/.github/workflows/linux-tutorials-test.yml b/.github/workflows/linux-tutorials-test.yml index dc5600a21..a304f97bb 100644 --- a/.github/workflows/linux-tutorials-test.yml +++ b/.github/workflows/linux-tutorials-test.yml @@ -1,38 +1,37 @@ -# 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: Tutorial tests on: - push: - branches: [master] - pull_request: - branches: [master] + push: + branches: [master] + pull_request: + branches: [master] permissions: - contents: read + contents: read jobs: - tutorial-test: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] - tutorial: ['Tianshou', 'CustomEnvironment', 'CleanRL', 'SB3/kaz', 'SB3/waterworld', 'SB3/connect_four', 'SB3/test'] # TODO: add back Ray once next release after 2.6.2 - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies and run tutorials - run: | - sudo apt-get install python3-opengl xvfb - export root_dir=$(pwd) - cd tutorials/${{ matrix.tutorial }} - pip install -r requirements.txt - pip uninstall -y pettingzoo - pip install -e $root_dir[testing] - AutoROM -v - for f in *.py; do xvfb-run -a -s "-screen 0 1024x768x24" python "$f"; done + tutorial-test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11'] + tutorial: [Tianshou, CustomEnvironment, CleanRL, SB3/kaz, SB3/waterworld, SB3/connect_four, SB3/test] # TODO: add back Ray once next release after 2.6.2 + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies and run tutorials + run: | + sudo apt-get install python3-opengl xvfb parallel + export PATH=/path/to/parallel:$PATH + export root_dir=$(pwd) + cd tutorials/${{ matrix.tutorial }} + pip install -r requirements.txt + pip uninstall -y pettingzoo + pip install -e $root_dir[testing] + AutoROM -v + for f in *.py; do xvfb-run -a -s "-screen 0 1024x768x24" python "$f"; done diff --git a/.github/workflows/macos-test.yml b/.github/workflows/macos-test.yml index ad780d207..ba848fd8d 100644 --- a/.github/workflows/macos-test.yml +++ b/.github/workflows/macos-test.yml @@ -1,30 +1,27 @@ -# 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: MacOS tests on: - push: - branches: [master] + push: + branches: [master] permissions: - contents: read + contents: read jobs: - macos-test: - runs-on: macos-11 - steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.8 - uses: actions/setup-python@v3 - with: - python-version: 3.8 - - name: Install dependencies - run: | - pip install -e .[all] - pip install -e .[testing] - AutoROM -v - - name: Full Python tests - run: | - pytest ./test/pytest_runner_test.py - pytest ./test/all_parameter_combs_test.py + macos-test: + runs-on: macos-11 + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3.8 + uses: actions/setup-python@v3 + with: + python-version: 3.8 + - name: Install dependencies + run: | + pip install -e .[all] + pip install -e .[testing] + AutoROM -v + - name: Full Python tests + run: | + pytest -v --cov=pettingzoo --cov-report term diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 26515d79f..c8cb6feb7 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,22 +1,20 @@ -# https://pre-commit.com -# This GitHub Action assumes that the repo contains a valid .pre-commit-config.yaml file. --- name: pre-commit on: - pull_request: - push: - branches: [master] + pull_request: + push: + branches: [master] permissions: - contents: read + contents: read jobs: - pre-commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 - - run: pip install pre-commit - - run: pre-commit --version - - run: pre-commit install - - run: pre-commit run --all-files + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - run: pip install pre-commit + - run: pre-commit --version + - run: pre-commit install + - run: pre-commit run --all-files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 08174efa7..7205ba055 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,81 +1,86 @@ +--- # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 - hooks: - - id: check-symlinks - - id: destroyed-symlinks - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-toml - - id: check-ast - - id: check-added-large-files - - id: check-merge-conflict - - id: check-executables-have-shebangs - - id: check-shebang-scripts-are-executable - - id: detect-private-key - - id: debug-statements - - id: mixed-line-ending - args: [ "--fix=lf" ] - - repo: https://github.com/python/black - rev: 23.3.0 - hooks: - - id: black - - repo: https://github.com/codespell-project/codespell - rev: v2.2.4 - hooks: - - id: codespell - args: - - --skip=*.css,*.js,*.map,*.scss,*.svg - - --ignore-words-list=magent - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - args: - - '--per-file-ignores=*/__init__.py:F401 test/all_parameter_combs_test.py:F405 pettingzoo/classic/go/go.py:W605' - - --extend-ignore=E203 - - --max-complexity=205 - - --max-line-length=300 - - --show-source - - --statistics - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - args: ["--profile", "black"] - - repo: https://github.com/asottile/pyupgrade - rev: v3.3.2 - hooks: - - id: pyupgrade - args: ["--py38-plus"] - - repo: https://github.com/pycqa/pydocstyle - rev: 6.3.0 - hooks: - - id: pydocstyle - args: - - --source - - --explain - - --convention=google - - --count + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-symlinks + - id: destroyed-symlinks + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-toml + - id: check-ast + - id: check-added-large-files + - id: check-merge-conflict + - id: check-executables-have-shebangs + - id: check-shebang-scripts-are-executable + - id: detect-private-key + - id: debug-statements + - id: mixed-line-ending + args: [--fix=lf] + - repo: https://github.com/python/black + rev: 23.3.0 + hooks: + - id: black + - repo: https://github.com/codespell-project/codespell + rev: v2.2.4 + hooks: + - id: codespell + args: + - --skip=*.css,*.js,*.map,*.scss,*.svg + - --ignore-words-list=magent + - repo: https://github.com/PyCQA/flake8 + rev: 6.0.0 + hooks: + - id: flake8 + args: + - --per-file-ignores=*/__init__.py:F401 test/all_parameter_combs_test.py:F405 pettingzoo/classic/go/go.py:W605 + - --extend-ignore=E203 + - --max-complexity=205 + - --max-line-length=300 + - --show-source + - --statistics + - repo: https://github.com/PyCQA/isort + rev: 5.12.0 + hooks: + - id: isort + args: [--profile, black] + - repo: https://github.com/asottile/pyupgrade + rev: v3.3.2 + hooks: + - id: pyupgrade + args: [--py38-plus] + - repo: https://github.com/pycqa/pydocstyle + rev: 6.3.0 + hooks: + - id: pydocstyle + args: + - --source + - --explain + - --convention=google + - --count # TODO: Remove ignoring rules D101, D102, D103, D105 (add docstrings to all public methods) - - --add-ignore=D100,D107,D101,D102,D103,D105 - exclude: "__init__.py$|^pettingzoo.test|^docs" - additional_dependencies: ["tomli"] - - repo: local - hooks: - - id: pyright - name: pyright - entry: pyright - language: node - pass_filenames: false - types: [python] - additional_dependencies: ["pyright"] - args: - - --project=pyproject.toml - - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.26.3 - hooks: - - id: check-github-workflows + - --add-ignore=D100,D107,D101,D102,D103,D105 + exclude: __init__.py$|^pettingzoo.test|^docs + additional_dependencies: [tomli] + - repo: local + hooks: + - id: pyright + name: pyright + entry: pyright + language: node + pass_filenames: false + types: [python] + additional_dependencies: [pyright] + args: + - --project=pyproject.toml + - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt + rev: 0.2.3 + hooks: + - id: yamlfmt + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.26.3 + hooks: + - id: check-github-workflows diff --git a/conftest.py b/conftest.py new file mode 100644 index 000000000..9bf11262e --- /dev/null +++ b/conftest.py @@ -0,0 +1,18 @@ +def pytest_markdown_docs_globals(): + import gymnasium + import shimmy + import supersuit + + import pettingzoo + from pettingzoo.utils.all_modules import all_environments + + libs = { + "pettingzoo": pettingzoo, + "gymnasium": gymnasium, + "shimmy": shimmy, + "supersuit": supersuit, + } + # Format: {"go_v5": , ...} + envs = {name.split("/")[1]: module for name, module in all_environments.items()} + libs.update(envs) + return libs diff --git a/docs/README.md b/docs/README.md index 88d091ebd..ca40d0417 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,3 +37,7 @@ To rebuild the documentation automatically every time a change is made: cd docs sphinx-autobuild -b dirhtml . _build ``` + +## Test the documentation +The plugin [pytest-markdown-docs](https://github.com/modal-labs/pytest-markdown-docs) allows us to test our documentation to ensure that example code runs successfully. To test, run the following command: +pytest docs --markdown-docs -m markdown-docs diff --git a/docs/api/parallel.md b/docs/api/parallel.md index a5f7abfce..d32e0b7b4 100644 --- a/docs/api/parallel.md +++ b/docs/api/parallel.md @@ -26,7 +26,7 @@ from pettingzoo.butterfly import pistonball_v6 parallel_env = pistonball_v6.parallel_env(render_mode="human") observations, infos = parallel_env.reset(seed=42) -while env.agents: +while parallel_env.agents: # this is where you would insert your policy actions = {agent: parallel_env.action_space(agent).sample() for agent in parallel_env.agents} diff --git a/docs/api/wrappers/pz_wrappers.md b/docs/api/wrappers/pz_wrappers.md index 51b40bc44..d3eb21c38 100644 --- a/docs/api/wrappers/pz_wrappers.md +++ b/docs/api/wrappers/pz_wrappers.md @@ -62,25 +62,11 @@ We wanted our pettingzoo environments to be both easy to use and easy to impleme You can apply these wrappers to your environment in a similar manner to the below examples: -To wrap a Parallel environment. -```python -from pettingzoo.utils import CaptureStdoutWrapper -from pettingzoo.butterfly import pistonball_v6 -parallel_env = pistonball_v6.env() -parallel_env = CaptureStdoutWrapper(parallel_env) - -observations, infos = parallel_env.reset() - -while parallel_env.agents: - actions = {agent: parallel_env.action_space(agent).sample() for agent in parallel_env.agents} # this is where you would insert your policy - observations, rewards, terminations, truncations, infos = parallel_env.step(actions) -``` - To wrap an AEC environment: ```python from pettingzoo.utils import TerminateIllegalWrapper -from pettingzoo.classic import rps_v2 -env = rps_v2.env() +from pettingzoo.classic import tictactoe_v3 +env = tictactoe_v3.env() env = TerminateIllegalWrapper(env, illegal_reward=-1) env.reset() @@ -95,6 +81,42 @@ env.close() ``` Note: Most AEC environments include TerminateIllegalWrapper in their initialization, so this code does not change the environment's behavior. +To wrap a Parallel environment. +```python +from pettingzoo.utils import BaseParallelWrapper +from pettingzoo.butterfly import pistonball_v6 + +parallel_env = pistonball_v6.parallel_env(render_mode="human") +parallel_env = BaseParallelWrapper(parallel_env) + +observations, infos = parallel_env.reset() + +while parallel_env.agents: + actions = {agent: parallel_env.action_space(agent).sample() for agent in parallel_env.agents} # this is where you would insert your policy + observations, rewards, terminations, truncations, infos = parallel_env.step(actions) +``` + +```{eval-rst} +.. warning:: + + Included PettingZoo wrappers currently do not support parallel environments, to use them you must convert your environment to AEC, apply the wrapper, and convert back to parallel. +``` +```python +from pettingzoo.utils import ClipOutOfBoundsWrapper +from pettingzoo.sisl import multiwalker_v9 +from pettingzoo.utils import aec_to_parallel + +parallel_env = multiwalker_v9.env(render_mode="human") +parallel_env = ClipOutOfBoundsWrapper(parallel_env) +parallel_env = aec_to_parallel(parallel_env) + +observations, infos = parallel_env.reset() + +while parallel_env.agents: + actions = {agent: parallel_env.action_space(agent).sample() for agent in parallel_env.agents} # this is where you would insert your policy + observations, rewards, terminations, truncations, infos = parallel_env.step(actions) +``` + ```{eval-rst} .. currentmodule:: pettingzoo.utils.wrappers diff --git a/docs/api/wrappers/shimmy_wrappers.md b/docs/api/wrappers/shimmy_wrappers.md index bfe9515f8..d39b1756f 100644 --- a/docs/api/wrappers/shimmy_wrappers.md +++ b/docs/api/wrappers/shimmy_wrappers.md @@ -25,7 +25,7 @@ The [Shimmy](https://shimmy.farama.org/) package (`pip install shimmy`) allows c To load a DeepMind Control [multi-agent soccer game](https://github.com/deepmind/dm_control/blob/main/dm_control/locomotion/soccer/README.md): -```python +```python notest from shimmy import DmControlMultiAgentCompatibilityV0 from dm_control.locomotion import soccer as dm_soccer @@ -39,13 +39,13 @@ while env.agents: ``` -To load an OpenSpiel game of [backgammon](https://github.com/deepmind/open_spiel/blob/master/docs/games.md#backgammon): -```python -from shimmy import OpenspielCompatibilityV0 -import pyspiel +To load an OpenSpiel game of [backgammon](https://github.com/deepmind/open_spiel/blob/master/docs/games.md#backgammon), wrapped with [TerminateIllegalWrapper](https://pettingzoo.farama.org/api/wrappers/pz_wrappers/#pettingzoo.utils.wrappers.TerminateIllegalWrapper): +```python notest +from shimmy import OpenSpielCompatibilityV0 +from pettingzoo.utils import TerminateIllegalWrapper -env = pyspiel.load_game("backgammon") -env = OpenspielCompatibilityV0(game=env, render_mode=None) +env = OpenSpielCompatibilityV0(game_name="chess", render_mode=None) +env = TerminateIllegalWrapper(env, illegal_reward=-1) env.reset() for agent in env.agent_iter(): @@ -61,7 +61,7 @@ for agent in env.agent_iter(): To load a Melting Pot [prisoner's dilemma in the matrix](https://github.com/deepmind/meltingpot/blob/main/docs/substrate_scenario_details.md#prisoners-dilemma-in-the-matrix) substrate: -```python +```python notest from shimmy import MeltingPotCompatibilityV0 env = MeltingPotCompatibilityV0(substrate_name="prisoners_dilemma_in_the_matrix__arena", render_mode="human") observations, infos = env.reset() diff --git a/docs/content/basic_usage.md b/docs/content/basic_usage.md index 2f3cd8836..54e02b8c9 100644 --- a/docs/content/basic_usage.md +++ b/docs/content/basic_usage.md @@ -25,8 +25,10 @@ env = pistonball_v6.env() Environments are generally highly configurable via arguments at creation, i.e.: ``` python -cooperative_pong.env(ball_speed=18, left_paddle_speed=25, -right_paddle_speed=25, is_cake_paddle=True, max_cycles=900, bounce_randomness=False) +from pettingzoo.butterfly import cooperative_pong_v5 + +cooperative_pong_v5.env(ball_speed=18, left_paddle_speed=25, +right_paddle_speed=25, cake_paddle=True, max_cycles=900, bounce_randomness=False) ``` ## Interacting With Environments @@ -34,11 +36,22 @@ right_paddle_speed=25, is_cake_paddle=True, max_cycles=900, bounce_randomness=Fa Environments can be interacted with using a similar interface to Gymnasium: ``` python -env.reset() +from pettingzoo.butterfly import cooperative_pong_v5 + +env = cooperative_pong_v5.env(render_mode="human") +env.reset(seed=42) + for agent in env.agent_iter(): observation, reward, termination, truncation, info = env.last() - action = env.action_space(agent).sample() # this is where you would insert your policy + + if termination or truncation: + action = None + else: + # this is where you would insert your policy + action = env.action_space(agent).sample() + env.step(action) +env.close() ``` The commonly used methods are: @@ -116,6 +129,8 @@ When an agent is terminated or truncated, it's removed from `agents`, so when th If you have a wrapped environment, and you want to get the unwrapped environment underneath all the layers of wrappers (so that you can manually call a function or change some underlying aspect of the environment), you can use the `.unwrapped` attribute. If the environment is already a base environment, the `.unwrapped` attribute will just return itself. ``` python +from pettingzoo.butterfly import knights_archers_zombies_v10 + base_env = knights_archers_zombies_v10.env().unwrapped ``` diff --git a/docs/content/environment_creation.md b/docs/content/environment_creation.md index 717c66bc2..38c37042c 100644 --- a/docs/content/environment_creation.md +++ b/docs/content/environment_creation.md @@ -87,7 +87,7 @@ from pettingzoo.utils.deprecated_module import DeprecatedModule knights_archers_zombies_v0 = DeprecatedModule("knights_archers_zombies", "v0", "v10") ``` This declaration tells the user that `knights_archers_zombies_v0` is deprecated and `knights_archers_zombies_v10` should be used instead. In particular, it gives the following error: -``` python +``` python notest from pettingzoo.butterfly import knights_archers_zombies_v0 knights_archers_zombies_v0.env() # pettingzoo.utils.deprecated_module.DeprecatedEnv: knights_archers_zombies_v0 is now deprecated, use knights_archers_zombies_v10 instead diff --git a/docs/content/environment_tests.md b/docs/content/environment_tests.md index b4577bb0b..369ffe98f 100644 --- a/docs/content/environment_tests.md +++ b/docs/content/environment_tests.md @@ -41,11 +41,11 @@ The seed test takes in a function that creates a pettingzoo environment. For exa from pettingzoo.test import seed_test, parallel_seed_test from pettingzoo.butterfly import pistonball_v6 env_fn = pistonball_v6.env -seed_test(env_fn, num_cycles=10, test_kept_state=True) +seed_test(env_fn, num_cycles=10) # or for parallel environments parallel_env_fn = pistonball_v6.parallel_env -parallel_seed_test(parallel_env_fn, num_cycles=10, test_kept_state=True) +parallel_seed_test(parallel_env_fn) ``` Internally, there are two separate tests. @@ -64,19 +64,17 @@ The max cycles test tests that the `max_cycles` environment argument exists and ``` python from pettingzoo.test import max_cycles_test from pettingzoo.butterfly import pistonball_v6 -env = pistonball_v6.env() -max_cycles_test(env) +max_cycles_test(pistonball_v6) ``` ## Render Test The render test checks that rendering 1) does not crash and 2) produces output of the correct type when given a mode (only supports `'human'`, `'ansi'`, and `'rgb_array'` modes). - ``` python from pettingzoo.test import render_test from pettingzoo.butterfly import pistonball_v6 -env = pistonball_v6.env() -render_test(env) +env_func = pistonball_v6.env +render_test(env_func) ``` The render test method takes in an optional argument `custom_tests` that allows for additional tests in non-standard modes. diff --git a/docs/environments/atari.md b/docs/environments/atari.md index 4839f94ac..a42e03f38 100644 --- a/docs/environments/atari.md +++ b/docs/environments/atari.md @@ -94,9 +94,9 @@ Here is some example usage for the Atari preprocessing: ``` python import supersuit -from pettingzoo.atari import space_invaders_v1 +from pettingzoo.atari import space_invaders_v2 -env = space_invaders_v1.env() +env = space_invaders_v2.env() # as per openai baseline's MaxAndSKip wrapper, maxes over the last 2 frames # to deal with frame flickering diff --git a/docs/environments/butterfly.md b/docs/environments/butterfly.md index 4e1262c03..49a08cc00 100644 --- a/docs/environments/butterfly.md +++ b/docs/environments/butterfly.md @@ -63,7 +63,7 @@ for agent in env.agent_iter(): observation, reward, termination, truncation, info = env.last() if termination or truncation: - action = None + action = None elif agent == manual_policy.agent: # get user input (controls are WASD and space) action = manual_policy(observation, agent) diff --git a/pettingzoo/atari/maze_craze/maze_craze.py b/pettingzoo/atari/maze_craze/maze_craze.py index e30a87996..5c3b77a87 100644 --- a/pettingzoo/atari/maze_craze/maze_craze.py +++ b/pettingzoo/atari/maze_craze/maze_craze.py @@ -42,7 +42,7 @@ Parameters specific to Maze Craze are ``` python -maze_craze.env(game_version="robbers", visibilty_level=0) +maze_craze_v3.env(game_version="robbers", visibilty_level=0) ``` `game_version`: Possibilities are "robbers", "race", "capture", corresponding to the 3 game versions described above diff --git a/pettingzoo/butterfly/cooperative_pong/cooperative_pong.py b/pettingzoo/butterfly/cooperative_pong/cooperative_pong.py index 44b1492a8..0751a12e7 100644 --- a/pettingzoo/butterfly/cooperative_pong/cooperative_pong.py +++ b/pettingzoo/butterfly/cooperative_pong/cooperative_pong.py @@ -9,7 +9,7 @@ This environment is part of the butterfly environments. Please read that page first for general information. -| Import | `from pettingzoo.butterfly import cooperative_pong_v4` | +| Import | `from pettingzoo.butterfly import cooperative_pong_v5` | |----------------------|--------------------------------------------------------| | Actions | Discrete | | Parallel API | Yes | @@ -37,7 +37,7 @@ ### Arguments ``` python -cooperative_pong_v4.env(ball_speed=9, left_paddle_speed=12, +cooperative_pong_v5.env(ball_speed=9, left_paddle_speed=12, right_paddle_speed=12, cake_paddle=True, max_cycles=900, bounce_randomness=False, max_reward=100, off_screen_penalty=-10) ``` diff --git a/pettingzoo/classic/hanabi/hanabi.py b/pettingzoo/classic/hanabi/hanabi.py index 626ae430a..1f108b310 100644 --- a/pettingzoo/classic/hanabi/hanabi.py +++ b/pettingzoo/classic/hanabi/hanabi.py @@ -32,13 +32,13 @@ Hanabi takes in a number of arguments defining the size and complexity of the game. Default is a full 2 player hanabi game. ``` python -hanabi_v5.env(colors=5, rank=5, players=2, hand_size=5, max_information_tokens=8, -max_life_tokens=3, observation_type="minimal") +hanabi_v5.env(colors=5, ranks=5, players=2, hand_size=5, max_information_tokens=8, +max_life_tokens=3, observation_type='minimal') ``` `colors`: Number of colors the cards can take (affects size of deck) -`rank`: Number of ranks the cards can take (affects size of deck) +`ranks`: Number of ranks the cards can take (affects size of deck) `hand_size`: Size of player's hands. Standard game is (4 if players >= 4 else 5) diff --git a/pettingzoo/mpe/simple_world_comm/simple_world_comm.py b/pettingzoo/mpe/simple_world_comm/simple_world_comm.py index d0642ea55..598c0d23e 100644 --- a/pettingzoo/mpe/simple_world_comm/simple_world_comm.py +++ b/pettingzoo/mpe/simple_world_comm/simple_world_comm.py @@ -51,7 +51,7 @@ ### Arguments ``` python -simple_world_comm.env(num_good=2, num_adversaries=4, num_obstacles=1, +simple_world_comm_v3.env(num_good=2, num_adversaries=4, num_obstacles=1, num_food=2, max_cycles=25, num_forests=2, continuous_actions=False) ``` diff --git a/pettingzoo/sisl/multiwalker/multiwalker.py b/pettingzoo/sisl/multiwalker/multiwalker.py index 567f9fc49..b398268e9 100644 --- a/pettingzoo/sisl/multiwalker/multiwalker.py +++ b/pettingzoo/sisl/multiwalker/multiwalker.py @@ -78,7 +78,7 @@ ``` python multiwalker_v9.env(n_walkers=3, position_noise=1e-3, angle_noise=1e-3, forward_reward=1.0, terminate_reward=-100.0, fall_reward=-10.0, shared_reward=True, -terminate_on_fall=True, remove_on_fall=True, terrain_legth=200, max_cycles=500) +terminate_on_fall=True, remove_on_fall=True, terrain_length=200, max_cycles=500) ``` diff --git a/pettingzoo/sisl/waterworld/waterworld.py b/pettingzoo/sisl/waterworld/waterworld.py index 3973856c2..d2de2eb21 100644 --- a/pettingzoo/sisl/waterworld/waterworld.py +++ b/pettingzoo/sisl/waterworld/waterworld.py @@ -82,7 +82,7 @@ ``` python waterworld_v4.env(n_pursuers=5, n_evaders=5, n_poisons=10, n_coop=2, n_sensors=20, -sensor_range=0.2,radius=0.015, obstacle_radius=0.2, +sensor_range=0.2,radius=0.015, obstacle_radius=0.2, n_obstacles=1, obstacle_coord=[(0.5, 0.5)], pursuer_max_accel=0.01, evader_speed=0.01, poison_speed=0.01, poison_reward=-1.0, food_reward=10.0, encounter_reward=0.01, thrust_penalty=-0.5, local_ratio=1.0, speed_features=True, max_cycles=500) diff --git a/pettingzoo/test/api_test.py b/pettingzoo/test/api_test.py index 868832777..f8718579c 100644 --- a/pettingzoo/test/api_test.py +++ b/pettingzoo/test/api_test.py @@ -71,7 +71,6 @@ def action_mask(): "texas_holdem_no_limit_v6", "texas_holdem_v4", "go_v5", - "hanabi_v4", "chess_v6", "connect_four_v3", "tictactoe_v3", @@ -93,7 +92,7 @@ def action_mask(): "texas_holdem_no_limit_v6", "texas_holdem_v4", "go_v5", - "hanabi_v4", + "hanabi_v5", "knights_archers_zombies_v10", "chess_v6", "connect_four_v3", diff --git a/pettingzoo/test/render_test.py b/pettingzoo/test/render_test.py index a4f4959f5..13091b81b 100644 --- a/pettingzoo/test/render_test.py +++ b/pettingzoo/test/render_test.py @@ -1,6 +1,9 @@ from __future__ import annotations +from typing import Callable + import numpy as np +from gymnasium.core import Env def collect_render_results(env): @@ -24,7 +27,7 @@ def collect_render_results(env): return results -def render_test(env_fn, custom_tests={}): +def render_test(env_fn: Callable[[], Env], custom_tests={}): env = env_fn(render_mode="human") render_modes = env.metadata.get("render_modes")[:] assert ( diff --git a/pettingzoo/utils/conversions.py b/pettingzoo/utils/conversions.py index 589754cb8..601a1fb06 100644 --- a/pettingzoo/utils/conversions.py +++ b/pettingzoo/utils/conversions.py @@ -124,6 +124,15 @@ def __init__(self, aec_env): self.metadata = aec_env.metadata + try: + self.render_mode = ( + self.aec_env.render_mode # pyright: ignore[reportGeneralTypeIssues] + ) + except AttributeError: + warnings.warn( + f"The base environment `{aec_env}` does not have a `render_mode` defined." + ) + # Not every environment has the .state_space attribute implemented try: self.state_space = self.aec_env.state_space @@ -420,6 +429,15 @@ def __init__(self, aec_env: AECEnv[AgentID, ObsType, Optional[ActionType]]): except AttributeError: pass + try: + self.render_mode = ( + self.aec_env.render_mode # pyright: ignore[reportGeneralTypeIssues] + ) + except AttributeError: + warnings.warn( + f"The base environment `{aec_env}` does not have a `render_mode` defined." + ) + @property def unwrapped(self): return self.aec_env.unwrapped diff --git a/pettingzoo/utils/wrappers/assert_out_of_bounds.py b/pettingzoo/utils/wrappers/assert_out_of_bounds.py index 7cf73ba30..84e713476 100644 --- a/pettingzoo/utils/wrappers/assert_out_of_bounds.py +++ b/pettingzoo/utils/wrappers/assert_out_of_bounds.py @@ -8,6 +8,9 @@ class AssertOutOfBoundsWrapper(BaseWrapper[AgentID, ObsType, ActionType]): """Asserts if the action given to step is outside of the action space.""" def __init__(self, env: AECEnv[AgentID, ObsType, ActionType]): + assert isinstance( + env, AECEnv + ), "AssertOutOfBoundsWrapper is only compatible with AEC environments" super().__init__(env) def step(self, action: ActionType) -> None: diff --git a/pettingzoo/utils/wrappers/capture_stdout.py b/pettingzoo/utils/wrappers/capture_stdout.py index 06f55d2e5..d74fa1e58 100644 --- a/pettingzoo/utils/wrappers/capture_stdout.py +++ b/pettingzoo/utils/wrappers/capture_stdout.py @@ -7,6 +7,9 @@ class CaptureStdoutWrapper(BaseWrapper): """Takes an environment which prints to terminal, and gives it an `ansi` render mode where it captures the terminal output and returns it as a string instead.""" def __init__(self, env: AECEnv): + assert isinstance( + env, AECEnv + ), "CaptureStdoutWrapper is only compatible with AEC environments" assert hasattr(env, "render_mode"), f"Environment {env} has no render_mode." assert ( env.render_mode == "human" # pyright: ignore[reportGeneralTypeIssues] diff --git a/pettingzoo/utils/wrappers/clip_out_of_bounds.py b/pettingzoo/utils/wrappers/clip_out_of_bounds.py index 7eb84665d..fb7a4bdf5 100644 --- a/pettingzoo/utils/wrappers/clip_out_of_bounds.py +++ b/pettingzoo/utils/wrappers/clip_out_of_bounds.py @@ -16,6 +16,9 @@ class ClipOutOfBoundsWrapper(BaseWrapper): def __init__(self, env: AECEnv): super().__init__(env) + assert isinstance( + env, AECEnv + ), "ClipOutOfBoundsWrapper is only compatible with AEC environments." assert all( isinstance(self.action_space(agent), Box) for agent in getattr(self, "possible_agents", []) diff --git a/pettingzoo/utils/wrappers/order_enforcing.py b/pettingzoo/utils/wrappers/order_enforcing.py index bc14954da..6b78c9d7d 100644 --- a/pettingzoo/utils/wrappers/order_enforcing.py +++ b/pettingzoo/utils/wrappers/order_enforcing.py @@ -27,6 +27,9 @@ class OrderEnforcingWrapper(BaseWrapper[AgentID, ObsType, ActionType]): """ def __init__(self, env: AECEnv[AgentID, ObsType, ActionType]): + assert isinstance( + env, AECEnv + ), "OrderEnforcingWrapper is only compatible with AEC environments" self._has_reset = False self._has_rendered = False self._has_updated = False diff --git a/pettingzoo/utils/wrappers/terminate_illegal.py b/pettingzoo/utils/wrappers/terminate_illegal.py index b4c242d57..2a0e521bf 100644 --- a/pettingzoo/utils/wrappers/terminate_illegal.py +++ b/pettingzoo/utils/wrappers/terminate_illegal.py @@ -1,3 +1,4 @@ +# pyright reportGeneralTypeIssues=false from __future__ import annotations from pettingzoo.utils.env import ActionType, AECEnv, AgentID, ObsType @@ -18,29 +19,40 @@ def __init__( super().__init__(env) self._illegal_value = illegal_reward self._prev_obs = None + self._prev_info = None def reset(self, seed: int | None = None, options: dict | None = None) -> None: self._terminated = False self._prev_obs = None + self._prev_info = None super().reset(seed=seed, options=options) def observe(self, agent: AgentID) -> ObsType | None: obs = super().observe(agent) if agent == self.agent_selection: self._prev_obs = obs + self._prev_info = self.infos[self.agent_selection] return obs def step(self, action: ActionType) -> None: current_agent = self.agent_selection if self._prev_obs is None: self.observe(self.agent_selection) - assert self._prev_obs - assert isinstance(self._prev_obs, dict) - assert ( - "action_mask" in self._prev_obs - ), "action_mask must always be part of environment observation as an element in a dictionary observation to use the TerminateIllegalWrapper" - _prev_action_mask = self._prev_obs["action_mask"] + if isinstance(self._prev_obs, dict): + assert self._prev_obs is not None + assert ( + "action_mask" in self._prev_obs + ), f"`action_mask` not found in dictionary observation: {self._prev_obs}. Action mask must either be in `observation['action_mask']` or `info['action_mask']` to use TerminateIllegalWrapper." + _prev_action_mask = self._prev_obs["action_mask"] + + else: + assert self._prev_info is not None + assert ( + "action_mask" in self._prev_info + ), f"`action_mask` not found in info for non-dictionary observation: {self._prev_info}. Action mask must either be in observation['action_mask'] or info['action_mask'] to use TerminateIllegalWrapper." + _prev_action_mask = self._prev_info["action_mask"] self._prev_obs = None + self._prev_info = None if self._terminated and ( self.terminations[self.agent_selection] or self.truncations[self.agent_selection] @@ -56,6 +68,7 @@ def step(self, action: ActionType) -> None: self.terminations = {d: True for d in self.agents} self.truncations = {d: True for d in self.agents} self._prev_obs = None + self._prev_info = None self.rewards = {d: 0 for d in self.truncations} self.rewards[current_agent] = float(self._illegal_value) self._accumulate_rewards() diff --git a/pyproject.toml b/pyproject.toml index fc29e42fd..5c59c9654 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,9 @@ testing = [ "AutoROM", "pytest", "pytest-cov", + "pytest-xdist", "pre-commit", + "pytest-markdown-docs" ] all = [ "multi_agent_ale_py==0.1.11", @@ -104,4 +106,4 @@ typeCheckingMode = "basic" reportMissingImports = false [tool.pytest.ini_options] -addopts = [ "--ignore-glob=*/__init__.py" ] +addopts = [ "--ignore-glob=*/__init__.py", "-n=auto", "--ignore=tutorials", "--ignore=docs/_scripts", "--ignore=conf.py"] diff --git a/tutorials/SB3/test/test_sb3_action_mask.py b/tutorials/SB3/test/test_sb3_action_mask.py index f8f803766..3835af393 100644 --- a/tutorials/SB3/test/test_sb3_action_mask.py +++ b/tutorials/SB3/test/test_sb3_action_mask.py @@ -6,7 +6,7 @@ chess_v6, gin_rummy_v4, go_v5, - hanabi_v4, + hanabi_v5, leduc_holdem_v4, texas_holdem_no_limit_v6, texas_holdem_v4, @@ -29,15 +29,15 @@ # More difficult environments which will likely take more training time MEDIUM_ENVS = [ leduc_holdem_v4, # with 10x as many steps it gets higher total rewards (9 vs -9), 0.52 winrate, and 0.92 vs 0.83 total scores - hanabi_v4, # even with 10x as many steps, total score seems to always be tied between the two agents + hanabi_v5, # even with 10x as many steps, total score seems to always be tied between the two agents tictactoe_v3, # even with 10x as many steps, agent still loses every time (most likely an error somewhere) + chess_v6, # difficult to train because games take so long, performance varies heavily ] # Most difficult environments to train agents for (and longest games # TODO: test board_size to see if smaller go board is more easily solvable HARD_ENVS = [ - chess_v6, # difficult to train because games take so long, 0.28 winrate even after 10x - go_v5, # difficult to train because games take so long + go_v5, # difficult to train because games take so long, may be another issue causing poor performance ] @@ -118,9 +118,7 @@ def test_action_mask_hard(env_fn): env_fn, num_games=100, render_mode=None, **env_kwargs ) - assert ( - winrate < 0.5 - ), "Policy should not perform better than 50% winrate" # 28% for chess, 0% for go + assert winrate > 0, "Policy should not perform better than 50% winrate" # 0% for go # Watch two games (disabled by default) # eval_action_mask(env_fn, num_games=2, render_mode="human", **env_kwargs)