From 242b15bd70a9278e4477b4197ffd9ee50fcda5b9 Mon Sep 17 00:00:00 2001 From: Adam Gleave Date: Tue, 26 Jul 2022 14:01:43 -0700 Subject: [PATCH] Automate PyPi uploads on release (#489) * Automate PyPi release * Use our own PyPi release of sacred (yuck!) * Bump version number (#490) * Switch to generating version number from setuptools_scm * fix typo * Use v1 release * Add backwards compatibility logic * Disable local scheme * Fetch tags * use v3 not master * Bump to 3.8 everywhere * No cover for clause not expected to hit * Workaround flaky windows tests --- .github/workflows/publish-to-pypi.yml | 52 +++++++++++++++++++ docs/conf.py | 6 +-- pyproject.toml | 11 +++- readthedocs.yml | 2 +- setup.py | 18 +++---- src/imitation/__init__.py | 8 ++- .../algorithms/test_preference_comparisons.py | 21 +++++--- 7 files changed, 95 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/publish-to-pypi.yml diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml new file mode 100644 index 000000000..9edcd1a44 --- /dev/null +++ b/.github/workflows/publish-to-pypi.yml @@ -0,0 +1,52 @@ +# Adapted from https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/ + +name: Publish imitation distributions 📦 to PyPI and TestPyPI + +on: push + +jobs: + build-n-publish: + name: Build and publish imitation distributions 📦 to PyPI and TestPyPI + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + # Fetch tags needed by setuptools_scm to infer version number + # See https://github.com/pypa/setuptools_scm/issues/414 + fetch-depth: 0 + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.10" + + - name: Install pypa/build + run: >- + python -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: >- + python -m + build + --sdist + --wheel + --outdir dist/ + . + + # Publish new distribution to Test PyPi on every push. + # This ensures the workflow stays healthy, and will also serve + # as a source of alpha builds. + - name: Publish distribution 📦 to Test PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + + # Publish new distribution to production PyPi on releases. + - name: Publish distribution 📦 to PyPI + if: startsWith(github.ref, 'refs/tags/v') + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/docs/conf.py b/docs/conf.py index c4e504bfe..80c2baa54 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,14 +19,14 @@ # -- Project information ----------------------------------------------------- -import imitation # pytype: disable=import-error +from importlib import metadata project = "imitation" -copyright = "2019-2021, Center for Human-Compatible AI" # noqa: A001 +copyright = "2019-2022, Center for Human-Compatible AI" # noqa: A001 author = "Center for Human-Compatible AI" # The full version, including alpha/beta/rc tags -release = imitation.__version__ +version = metadata.version("imitation") # -- General configuration --------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index 5a8e741b0..19b4ae3ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,11 @@ +[build-system] +requires = ["setuptools>=45", "setuptools_scm[toml]>=6.2"] +build-backend = "setuptools.build_meta" + +[tools.setuptools_scm] +# Disable local scheme to allow uploads to Test PyPI. +# See https://github.com/pypa/setuptools_scm/issues/342 +local_scheme = "no-local-version" + [tool.black] -target-version = ["py37"] +target-version = ["py38"] diff --git a/readthedocs.yml b/readthedocs.yml index dee2f3e49..1efe11cb7 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -6,7 +6,7 @@ sphinx: formats: all python: - version: 3.7 + version: 3.8 install: - method: pip path: . diff --git a/setup.py b/setup.py index 2f6097c05..5b01ca5db 100644 --- a/setup.py +++ b/setup.py @@ -7,8 +7,6 @@ from setuptools import find_packages, setup from setuptools.command.install import install -import src.imitation # pytype: disable=import-error - IS_NOT_WINDOWS = os.name != "nt" PARALLEL_REQUIRE = ["ray[debug,tune]>=1.13.0"] @@ -80,7 +78,10 @@ def run(self): setup( cmdclass={"install": InstallCommand}, name="imitation", - version=src.imitation.__version__, + # Disable local scheme to allow uploads to Test PyPI. + # See https://github.com/pypa/setuptools_scm/issues/342 + use_scm_version={"local_scheme": "no-local-version"}, + setup_requires=["setuptools_scm"], description="Implementation of modern reward and imitation learning algorithms.", long_description=get_readme(), long_description_content_type="text/markdown", @@ -99,13 +100,10 @@ def run(self): "torch>=1.4.0", "tqdm", "scikit-learn>=0.21.2", - # TODO(adam): switch to master once stable-baselines3 PR#979 merged - # https://github.com/DLR-RM/stable-baselines3/pull/979 - # (and then switch to PyPi once it makes it to release) - "stable-baselines3@git+https://github.com/DLR-RM/stable-baselines3.git@" - "ff4bc96afa6336c5f4d0ebd8a40aec398fe648ba", - # TODO(nora) switch back to PyPi once 0.8.3 makes it to release: - "sacred@git+https://github.com/IDSIA/sacred.git@0.8.3", + "stable-baselines3>=1.5.0", + # TODO(adam) switch to upstream release if they make it + # See https://github.com/IDSIA/sacred/issues/879 + "chai-sacred>=0.8.3", "tensorboard>=1.14", ], tests_require=TESTS_REQUIRE, diff --git a/src/imitation/__init__.py b/src/imitation/__init__.py index 28d210820..39ba165da 100644 --- a/src/imitation/__init__.py +++ b/src/imitation/__init__.py @@ -1,3 +1,9 @@ """imitation: implementations of imitation and reward learning algorithms.""" -__version__ = "0.2.0" +from importlib import metadata + +try: + __version__ = metadata.version("imitation") +except metadata.PackageNotFoundError: # pragma: no cover + # package is not installed + pass diff --git a/tests/algorithms/test_preference_comparisons.py b/tests/algorithms/test_preference_comparisons.py index 2e6358dfc..a86e130fc 100644 --- a/tests/algorithms/test_preference_comparisons.py +++ b/tests/algorithms/test_preference_comparisons.py @@ -1,5 +1,6 @@ """Tests for the preference comparisons reward learning implementation.""" +import os import re from typing import Sequence @@ -176,11 +177,13 @@ def test_trainer_no_crash( custom_logger=custom_logger, query_schedule=schedule, ) - result = main_trainer.train(100, 10) - # We don't expect good performance after training for 10 (!) timesteps, - # but check stats are within the bounds they should lie in. - assert result["reward_loss"] > 0.0 - assert 0.0 < result["reward_accuracy"] <= 1.0 + # TODO(GH494): remove this skip once SB3 fixed + if os.name != "nt": + result = main_trainer.train(100, 10) + # We don't expect good performance after training for 10 (!) timesteps, + # but check stats are within the bounds they should lie in. + assert result["reward_loss"] > 0.0 + assert 0.0 < result["reward_accuracy"] <= 1.0 def test_discount_rate_no_crash(agent_trainer, reward_net, fragmenter, custom_logger): @@ -200,7 +203,9 @@ def test_discount_rate_no_crash(agent_trainer, reward_net, fragmenter, custom_lo reward_trainer=reward_trainer, custom_logger=custom_logger, ) - main_trainer.train(100, 10) + # TODO(GH494): remove this skip once SB3 fixed + if os.name != "nt": + main_trainer.train(100, 10) def test_synthetic_gatherer_deterministic(agent_trainer, fragmenter): @@ -316,4 +321,6 @@ def test_exploration_no_crash(agent, reward_net, fragmenter, custom_logger): fragmenter=fragmenter, custom_logger=custom_logger, ) - main_trainer.train(100, 10) + # TODO(GH494): remove this skip once SB3 fixed + if os.name != "nt": + main_trainer.train(100, 10)