Repository: mtazzari/uvplot (language: python)

Issue:
Automate PyPI releases
Automate PyPi releases to Fix #50 .
In doing so, it proved necessary to move from setting the setup configuration and PyPI metadata dynamically in `setup.py` to statically in `setup.cfg`.
This also requires to drop support for Python 2.7, which Fixes #52  
Drop support to Python 2.7
As of Jan 2021 Python 2.7 is not supported anymore:


> DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml
new file mode 100644
index 0000000..f83c2de
--- /dev/null
+++ b/.github/workflows/publish-to-pypi.yml
@@ -0,0 +1,43 @@
+name: Publish Python 🐍 distributions 📦 to TestPyPI and PyPI
+
+on:
+  push:
+    branches:
+      # Push events only on master branch
+      - master
+
+jobs:
+  build-n-publish:
+    name: Build and publish Python 🐍 distributions 📦 to TestPyPI and PyPI
+    runs-on: ubuntu-20.04
+    steps:
+      - uses: actions/checkout@v2
+      - name: Set up Python 3.7
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.7
+      - 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/
+          .
+      - name: Publish distribution 📦 to Test PyPI
+        if: startsWith(github.ref, 'refs/tags')
+        uses: pypa/gh-action-pypi-publish@master
+        with:
+          password: ${{ secrets.TEST_PYPI_API_TOKEN }}
+          repository_url: https://test.pypi.org/legacy/
+      - name: Publish distribution 📦 to PyPI
+        if: startsWith(github.ref, 'refs/tags')
+        uses: pypa/gh-action-pypi-publish@master
+        with:
+          password: ${{ secrets.PYPI_API_TOKEN }}
\ No newline at end of file
diff --git a/docs/install.rst b/docs/install.rst
index 440b3c9..7758cf0 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -15,7 +15,7 @@ By far the easiest way to install |uvplot| is via :code:`pip`:
 
     pip install uvplot
 
-|uvplot| works in Python 2.7, 3.6, 3.7, 3.8, and 3.9.
+|uvplot| works in Python 3.6, 3.7, 3.8, and 3.9.
 
 Using uvplot inside CASA
 ------------------------
diff --git a/github_deploy_key_mtazzari_uvplot.enc b/github_deploy_key_mtazzari_uvplot.enc
deleted file mode 100644
index 4d1c520..0000000
--- a/github_deploy_key_mtazzari_uvplot.enc
+++ /dev/null
@@ -1,1 +0,0 @@
-gAAAAABaeWPegcJcaW7LOv_F0bK0mWoj1R8EbDJiwjtweV-uDT6wH1u7rOJ5jD9kYAtzr9ixsB0dnzZ-BoSWlRoJNZl9HUgJli8QNbW9s2PKcGqr90jkHGfwPljX5trTj9_9n8qxAkvLtb9QsHPV4naVkCNXBNmBTOFBgaLvkHEg98QwLBeZi23IlvHpFcZxJFPjzFXndhvPGgMZAMbwj7PY6uYxm5gnbJNrnErBhByl5K4EV34g_P_FNUgpF5SgTVd1-sonJPKIiMurT0xKr0g48RNelZpptv8Z6INdzl-9NHNQiaTscGaY6OEK7rdX8ITOnx9CeU-xdQqBa-KJ7j4kJI4f4T7OFtRCHIdqMr6V63YYHPQXNrA0QxeTyBAueSNksk1I3wLVzv7hOhVJ5ywkEDHQayaqr7AmbjmfOvoHkv03pVC6d0jwsruph6lB66dkInsB4tQFJ5UEQS9Cyk8eAS4BgWVx_7sFuipr153y3Fdg0tHbgbKwHqglcf6XcBFCDy-ksEOlUsMCDP0pQ5pD9CYYBR5GXcJc5zwJD1D2vx5ohjSrIo3mnBf2_bUg-vMARoq4XNcSvqTeTONDzDO1ltXF2S-YYwRKZSZQpFkFQXSMFlt76GBS7NppZvQusvVKPRgzDcMimQyE2mqp2ApguQUCbE19jWg-i83gQQ7cx046jC9o5UNd5DAgxvWzRd03PoKhmuTzrGahQePK7VcYdow6iFNsfSSa4jI5u-pdnRAbbn4_i5ZNiSpU2wv5GbvG3gLsugT4i_KcPLDf1otJfNyBP8Bz2ZqceNbBdIEJEmkQJcVWZqtnDNexiEWljmT_Tgus-wc0FLoN_hjLMvSsOLgzcD8X3NLBgJqYj90bfABvB4n8ZFYSFdx4JqtLSUceQVtgHhtWBjJfiW2IT81KgfzhZTj346N3UTuY3vY9bVz1crdZ84h2a8BJDewORLYQX9u4-vDSNZ1eqf7l__dWb-vB2lhdMXRpR_GtLYYLsYdQFEYGYL_1XbCnkFRONLP6uGs33d7dDj0n5jB9--izK0-3_sY9vOaoAi-rSRPeGSIhfB7TUAR4LfGxXavEA6qo02bnMNYSa-r6lF27ftXBIT6WDeJXDQRTU4CWkjBBH9seu3n9pOGTi7gJ31ZVMvhfFGbWSjDXbUSjNj5XMAyIU5CTjV3sIoVyQxbjVgTL00o664keq_eGlU0sp38UES7DAdhGC5JuqwGuIV4F4QJMciRwbEwBSv4mOvLZo8WAaO2-XpXbT7FTEB_-Eb-hQmy60pMnwt6QI7hTy0VL-SVkiq-yHUwLK-y5-MJrq5H2PQBFJLGXBxBW9nMQIXwrgT0cG4XQi-1wb-aciZheo86D8LuOYjUf8f2iLwtUK06VeJYHezj3yun_-CKj3PVIAGIoir2_RNUAZ7CRGwjzcnHqbmI1fI5Y0T6zmRovCfX0wenoBGB5V-Dtwgu8_xB6XBb-2sVfr675GJ7ulkt4Kn_s1tAf_OKtglsCj19_CvB_kqtegO3N0aMrHKmADAbSs9sx3JMC6icdicJpIjk8zSGlnkVbn4S9kqw4-exnHG6D0mrJJp0YinuVXVghBAKoybZs_vnaoLSqba2do7uxJ716sH0IA3JDCFaVQFfYlWZsHhMi4MIG5bqMV_K-moBRb9P645BagNlolJYyTiPDTB1hbFoBKajDI8tZwsViKHaNJDsQjGwemAz_QWEc7SIjlYWd6xPWvZdP8eOD0L80DZ8P7cIkWed29x9CT3SDO5c2B4OuS-2DrQpJeZD-fN6s1baDESK28fZe1wabMLFLCYrp1YkubVOX9isKIjilfj5G7V0tHAm7v5SUA5a4yW5Vqojy3q_4uNj0efa73trNLKXG9vNSp0Pt-kDaRVE7x1-KYcBhs1Kpez6CGipVzoW-Mz-w5alRIqCn-fPcTIjwPZg8EidFOCaclVR2lg-aylAEKIcZf4Oy0lKV0Iar6R_PTLze5OYleLLeeBTf4TSQhzGsdtkbwuWbSiZfd3-1OQSUvQ4sRzwGQzggzRg9KIN8UxgNrTchzxjXK2lCTWubwUhNBpFnJwgfiLAKiVfZNxlYWaMybOGSKF8WdObjYOe-DEOUG-O495FFrvt1GiPeeq67K9_BKcKuZxDZ2_k7MMw2D9tVkfKyw1JKOjtWDVzSkHYpVuyA0nLUH-uI9cipTDhiCFfsBYK5VZrwaDDaClWbI-WylHd-pW-k4m8jCVg-0kbDAvFTh3SQry8yWwxyoPOkNEWhCjpRFkVjREjaMCUMvNbURpbqxjooZwuanxw6aNbI-bYN07J74WrioKHlIbYNhlAAztchkKVoMXHtgvS7H_84vBOGvfeSbLOE7QUrcm0IpZIeAcvOBn6bG2bBtJiqi0xGRxPinIy1n_LSYyEbfvuaViTRIc8L442JeuBnO1DCSjBxAQHT9fH3TIaIc_T8sn3z29TLQH2sifk6SaD5QoYvd-sdmhStsIabmKu8Ct82UAgV1CDkka6Sg93bx5xR5aYuvwLWNVbaX6n9kZzSrRTYz_0aebBBsKODFYnf4cH-LaBFe9TEjEP39oxm7mYIo0L9xD_S0mlDIpZAqfgmsPMmBQNXUAKXxbAsyZBglt6qUmiqCYW06OQ82RB3EFNLJg53v0bGR4OeEe5-Lva0oCdQXWXRbrFQRvgS1yuftrxGpQNnaIHpW8XUlb1C22WrnlDSeeYJYfDBFPE58DYLaZWG5MiJywqf-vZceToqoQuZLzIKKtTNtDZ5rrl0A4JnKA2UZOW2H1q8aCi39peS7gCBWzSB5r3LZVRMsBrwrYIjQbo0b__zqzGtRdxybK7jM2mAuBWi0wbrhA_Rxk1rE60oY43JRjYW7KSn1JKysNLfSUnprHpZdKHiQ0IXCRc3ea8fDnZaCiMjJQiTc_JdHAjrbGhQFDNNROU77V0uy4xYekwMo9jL5PeD3qqb5HXbdzRDRhaNTY-LyKOmFFjxXEheOXHozoD9JpGwzp1N9mgAA9AomKxZjmA6yvil8ts66WbjfRLIenRp4FZwAULWJ4udrYu6rdhQ5e2Iw6K8gqOdo9bz0IycyLyPHh90f4nTXb_QqvI4RHtN-bTgY0YAboI8SxBxY-nPF2xqijZ9xCUxmRrXjU385zXABYg7hSUrQ-Cq3xg9A-q9hDmsyxq4NLrKgscKrC_vlNdSlI98-mTVVZTDjmbsvgM5PA24Nw6ddyTP9P9_oUUUWF7dBOXpDDrDdksUs7cqKDUjjlniqxXR9ptrR1_a_zoPtOF0QMwiSKi7qkYEO4Dy5Fi0JTz-aRrini72dFsD2FHcGtfwW45ftvfEez15CehBd5sKPUKTpm85llGWnp1xFs6_DXJ8DuNOMRxSufULvMIotLErYktphueU6JkfcoFUysEhZLV3nnIIzP1xq9nvLNfca_hlJc__sDL07k8WNj3vpgBUn_oXKHcpo-3RUCP9rx8WxNiB37RN28pjcT5B-02aBtQ7PcClhHD-td7mo7r2Bp6tEXKLuxFggHe2kPkF7E-2BTg5i8SWuFiGrBaY7AviVMHvrodHbwZ1FUNx9hui-pui2Te8kn4E-p7TUhbYl9bnAFuE2ZVg6nS0wqTHbAIOIqJomctYziGMJ62fTPvK_wIhmJNY-4mbwz7uo5xM-JNhxAT7BtQq8foA3Q113KTABH0Pc5G8gy9XfNuFJetyPEgub0iDg2VHrHHho9Y85qVef40BCyEpivGmkWrIgrpCS9B860fLsST91GQpgA2jT79WlkMqk1Pme7kx9CLdjLPbIiDoZJm-xBbHh4mT22aj76vT9SAeMhAIEz1sB8eq4dheAfteyL23BseUTD9AOgfvf3LLfx502TZRsRcav5LuTKjum7HXApQQWfNtJVKINUWMulKIYQ5tmicl6BGjTksDTOerbtv8jfyiV_FsPIoaPtT9TGYaflAf5npwSQlI5k81m0fFgYZSmPwd0curV0Cz08F7ocOFQv9s1e22AnSaeq3mW0wTB-rvesg5uQllzyVKUpuFQac4M6VIMp4ypR59wWNqtbQBmPqmkjV1GghCIhdK0GG5H76yNS7Vt8724b93O5Qxrjj9QOSdFW4YpZkf27DzRbsDKT2ZGDZY2h_qEU50RU_hs-8SH3QxLyAUEjGTQsNPnmEVlrtUvSlF3OxZZPM3UxSuPBsv7GaodTAj-2rQCODPBg-OsCWoUKglM7-ms52IwzbkM5m1Dv6kUnci7UMIpk-04Z2ZB7D_S4q2nUaBEkY8aIHdCphLRFVQyipjVRpx3AA67AJJKLj65x2oL09HxDV52nA7JYfSeKPm5fU6M8BEF9V9DzhY5n7EExmwvg3Wbx21y6T3LWaqg4u8IXj2sD62GNgAX_rSPNqcez7pks5nmvVt0gg=
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..ba2d99c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,10 @@
+[build-system]
+
+# Minimum requirements for the build system to execute.
+# PEP 508 specifications.
+requires = [
+    "setuptools>=42",
+    "wheel"
+]
+
+build-backend = "setuptools.build_meta"
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..c677cf9
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,42 @@
+# to set version dynamically: https://github.com/pypa/setuptools/issues/1724#issuecomment-627241822
+
+[metadata]
+name = uvplot
+version = attr: uvplot.__version__
+author = Marco Tazzari
+author_email = mtazzari@gmail.com
+description = Utilities for handling and plotting interferometric visibilities.
+long_description = file: README.md
+long_description_content_type = text/markdown
+license = LGPLv3
+license_file = LICENSE.txt
+include_package_data = True
+url = https://github.com/mtazzari/uvplot
+project_urls =
+    Bug Tracker = https://github.com/mtazzari/uvplot/issues
+classifiers =
+    Development Status :: 5 - Production/Stable
+    License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
+    Intended Audience :: Developers
+    Intended Audience :: Science/Research
+    Operating System :: MacOS :: MacOS X
+    Operating System :: POSIX :: Linux
+    Programming Language :: Python :: 3.6
+    Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3.9
+keywords =
+    science
+    astronomy
+    interferometry
+
+[options]
+packages = uvplot
+
+# python_requires docs: https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
+python_requires = >=3.6
+
+# PEP 440 - pinning package versions: https://www.python.org/dev/peps/pep-0440/#compatible-release
+install_requires =
+    numpy>=1.9
+    matplotlib
diff --git a/setup.py b/setup.py
index 1739e88..2ca2946 100644
--- a/setup.py
+++ b/setup.py
@@ -2,47 +2,5 @@
 # coding=utf-8
 from setuptools import setup
 
-# read version number
-exec(open("uvplot/_version.py", "r").read())
-
-# use README as long_description (for PyPI)
-try:
-    long_description = open("README.md", "r", encoding="utf-8").read()
-except TypeError:
-    # under Python 2.7 the `encoding` keyword doesn't exist.
-    print(
-        "DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. "
-        "Please upgrade your Python as Python 2.7 won't be maintained after that date. "
-        "A future version of uvplot will drop support for Python 2.7. "
-    )
-    long_description = open("README.md", "r").read()
-
-
-setup(
-    name="uvplot",
-    version=__version__,
-    packages=["uvplot"],
-    author="Marco Tazzari",
-    author_email="mtazzari@gmail.com",
-    description="Utilities for handling and plotting interferometric visibilities.",
-    long_description=long_description,
-    install_requires=["numpy>=1.9", "matplotlib"],
-    license="LGPLv3",
-    url="https://github.com/mtazzari/uvplot",
-    download_url="https://github.com/mtazzari/uvplot/archive/{}.tar.gz".format(
-        __version__
-    ),
-    keywords=["science", "astronomy", "interferometry"],
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "Intended Audience :: Science/Research",
-        "Operating System :: OS Independent",
-        "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
-        "Programming Language :: Python :: 2.7",
-        "Programming Language :: Python :: 3.6"
-        "Programming Language :: Python :: 3.7"
-        "Programming Language :: Python :: 3.8"
-        "Programming Language :: Python :: 3.9"
-    ],
-)
+# setup configuration is in `setup.cfg`
+setup()
diff --git a/uvplot/__init__.py b/uvplot/__init__.py
index 2a6a7c8..d16249c 100644
--- a/uvplot/__init__.py
+++ b/uvplot/__init__.py
@@ -1,4 +1,4 @@
-from ._version import __version__
+__version__ = '0.2.11'
 
 import matplotlib
 
diff --git a/uvplot/_set_unique_version.py b/uvplot/_set_unique_version.py
new file mode 100644
index 0000000..4c6e15f
--- /dev/null
+++ b/uvplot/_set_unique_version.py
@@ -0,0 +1,27 @@
+# This script makes the version number unique by adding a timestamp to the semantic version.
+# This is useful for testing the push to TestPyPI, which does not allow multiple uploads
+# with same version name.
+
+# initial plan was to add the branch name and commit sha
+# import subprocess
+# git_commit_sha = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).strip(b"\n")
+# git_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).strip(b"\n")
+
+# However, PEP440 forbids usage of hashes in version numbers
+# https://stackoverflow.com/questions/57912086/twine-upload-dist-get-an-error-is-an-invalid-value-for-version
+
+import time
+
+# read current version number
+with open("uvplot/__init__.py", "r") as f:
+    lines = f.readlines()
+
+print(f"Detected version: {lines[0].encode()}")
+
+# replace version number, e.g. '0.2.10' into '0.2.10.<current timestamp>'
+lines[0] = lines[0].replace("'\n", f".{int(time.time())}'\n")
+print(f"New version: {lines[0].encode()}")
+
+# save new version number
+with open("uvplot/__init__.py", "w") as g:
+    g.writelines(lines)
diff --git a/uvplot/_version.py b/uvplot/_version.py
deleted file mode 100644
index 2418de5..0000000
--- a/uvplot/_version.py
+++ /dev/null
@@ -1,1 +0,0 @@
-__version__ = '0.2.11'
\ No newline at end of file
diff --git a/uvplot/uvtable.py b/uvplot/uvtable.py
index cca739c..80ae06f 100644
--- a/uvplot/uvtable.py
+++ b/uvplot/uvtable.py
@@ -9,12 +9,7 @@
 import numpy as np
 import matplotlib.pyplot as plt
 from matplotlib.gridspec import GridSpec
-
-try:
-    from json.decoder import JSONDecodeError
-except ImportError:
-    # Python 2.7 does not have JSONDecodeError (which is a subclass of ValueError)
-    JSONDecodeError = ValueError
+from json.decoder import JSONDecodeError
 
 from .constants import clight
 


Test patch:
diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml
new file mode 100644
index 0000000..50a8eac
--- /dev/null
+++ b/.github/workflows/publish-to-test-pypi.yml
@@ -0,0 +1,46 @@
+name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI
+
+# branch filtering:
+# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
+
+on:
+  push:
+    branches:
+      # Push events to all branches except master
+      # https://stackoverflow.com/questions/57699839/github-actions-how-to-target-all-branches-except-master
+      - '**'
+      - '!master'
+
+jobs:
+  build-n-publish:
+    name: Build and publish Python 🐍 distributions 📦 to TestPyPI
+    runs-on: ubuntu-20.04
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Set up Python 3.7
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.7
+      - name: Set a temporary unique version number
+        # TestPyPI does not allow uploading two packages with same version number
+        run: python uvplot/_set_unique_version.py
+      - 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/
+          .
+      - name: Publish distribution 📦 to Test PyPI
+        uses: pypa/gh-action-pypi-publish@master
+        with:
+          password: ${{ secrets.TEST_PYPI_API_TOKEN }}
+          repository_url: https://test.pypi.org/legacy/
\ No newline at end of file
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index a11e5ef..8636e06 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -10,7 +10,7 @@ jobs:
 
     strategy:
       matrix:
-        python-version: [2.7, 3.6, 3.7, 3.8, 3.9]
+        python-version: [3.6, 3.7, 3.8, 3.9]
 
     steps:
       # Checks out a copy of your repository on the ubuntu-latest machine