Skip to content

Commit

Permalink
Merge pull request #185 from casparvl/setuptools_scm_versioning
Browse files Browse the repository at this point in the history
Add setuptools_scm for pyproject.toml, setup.cfg and setup.py
  • Loading branch information
smoors authored Oct 25, 2024
2 parents f321fc5 + cbefb7a commit 82512b1
Show file tree
Hide file tree
Showing 7 changed files with 395 additions and 4 deletions.
126 changes: 126 additions & 0 deletions .github/workflows/automatic_versioning.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions
name: Test version for tarball without git metadata
on: [push, pull_request, workflow_dispatch]
permissions: read-all
jobs:
test_versioning_from_tarball:
# ubuntu <= 20.04 is required for python 3.6
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11']
steps:
# - name: Check out repository
# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# with:
# persist-credentials: false
# fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0
with:
python-version: ${{ matrix.python-version }}

- name: Install setuptools
run: |
if [[ "${{ matrix.python-version }}" == "3.6" ]]; then
# system installed setuptools version in RHEL8 and CO7
python -m pip install --user setuptools==39.2.0
fi
- name: Install setuptools_scm
run: |
if [[ "${{ matrix.python-version }}" == "3.6" ]]; then
python -m pip install --user 'setuptools_scm>=4.0.0,<=4.1.2'
else
python -m pip install --user setuptools_scm
fi
- name: Check python and setuptools versions
run: |
python --version
python -m pip --version
python -c 'import setuptools; print("setuptools", setuptools.__version__)'
python -m pip show setuptools_scm | grep Version
- name: Download and extract tarball for current commit
run: |
wget "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/archive/$GITHUB_SHA.tar.gz"
tar -xzf "$GITHUB_SHA.tar.gz"
# Check current directory contents
find .
- name: Check version when running against uninstalled git clone
run: |
echo "importing eessi.testsuite from:"
original_pythonpath=$PYTHONPATH
export PYTHONPATH="$PWD/test-suite-$GITHUB_SHA:$PYTHONPATH"
echo "PYTHONPATH: $PYTHONPATH"
python3 -c "import eessi.testsuite; print(eessi.testsuite.__file__)"
uninstalled_version=$(python3 -c "import eessi.testsuite; print(eessi.testsuite.__version__)")
echo "Version from uninstalled git clone: $uninstalled_version"
fallback_version=$(grep -oP 'fallback_version\s*=\s*"\K[^"]+' "test-suite-$GITHUB_SHA/pyproject.toml")
echo "Testing if this version is the fallback version from pyproject.toml ..."
if [[ "$uninstalled_version" != "$fallback_version" ]]; then
echo "Version $uninstalled_version not equal to $fallback_version"
exit 1
else
echo "... yes!"
fi
export PYTHONPATH="$original_pythonpath"
- name: Install from extracted tarball
run: |
# Make sure we get the fallback version from the pyprject.toml before changing workdir
fallback_version=$(grep -oP 'fallback_version\s*=\s*"\K[^"]+' "test-suite-$GITHUB_SHA/pyproject.toml")
# Make it easier to figure out CI issues in case of CI failures related to SCM versioning
export SETUPTOOLS_SCM_DEBUG=1
# Change dir to the extracted tarball
cd "test-suite-$GITHUB_SHA"
python -m pip install . --user
echo "Checking contents of .local"
find $HOME/.local
# make sure we are not in the source directory
cd $HOME
echo "Checking if file 'eessi/testsuite/_version.py' was generated by setuptools_scm":
cat $HOME/.local/lib/python${{ matrix.python-version}}/site-packages/eessi/testsuite/_version.py
echo "Checking if version can be imported directly from the version file"
if [[ "${{ matrix.python-version }}" == "3.6" ]]; then
versionfile_version=$(python -c 'from eessi.testsuite._version import version; print(version)')
else
versionfile_version=$(python -c 'from eessi.testsuite._version import __version__; print(__version__)')
fi
echo "Version from version file: $versionfile_version"
echo "Checking if we can import the __version__ from eessi.testsuite"
installed_version=$(python -c 'import eessi.testsuite; print(eessi.testsuite.__version__)')
echo "Version from installed testsuite: $installed_version"
# Read the fallback version from the pyproject.toml
echo "Testing if this is the fallback version from pyproject.toml ..."
if [[ "$installed_version" != "$fallback_version" ]]; then
echo "Version $installed_version not equal to $fallback_version"
exit 1
else
echo "... yes!"
fi
echo "Checking if the version imported from eessi.testsuite matches that from the version file ..."
if [[ "$versionfile_version" != "$installed_version" ]]; then
echo "Version $versionfile_version not equal to $installed_version"
exit 1
else
echo "... yes!"
fi
47 changes: 47 additions & 0 deletions .github/workflows/check_versions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions
name: Test fallback_version and version in run_reframe.sh against tags
on: [push, pull_request, workflow_dispatch]
permissions: read-all
jobs:
test_fallback_version_against_tags:
# ubuntu <= 20.04 is required for python 3.6
runs-on: ubuntu-20.04
strategy:
fail-fast: false
steps:
- name: Check out repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
fetch-depth: 0

- name: Check fallback version and version used in run_reframe.sh
run: |
# Get fallback version
fallback_version=$(grep -oP 'fallback_version\s*=\s*"\K[^"]+' "pyproject.toml")
# Prepend fallback version with 'v', as that is also the case for the other two version strings
fallback_version="v$fallback_version"
# Get version from run_reframe.sh
run_reframe_testsuite_version=$(grep -oP 'EESSI_TESTSUITE_BRANCH\s*=\s*[^v]*\K[^"\x27]*' "CI/run_reframe.sh")
# Grab the tag for the highest version, by sorting by (semantic) version, and then filtering on patterns
# that match a pattern like v0.1.2. Finally, we grab the last to get the highest version
most_recent_version=$(git tag --sort=version:refname | grep -P "v[0-9]+\.[0-9]+\.[0-9]+" | tail -n 1)
echo "Testing if fallback version and EESSI_TESTSUITE_BRANCH version in CI/run_reframe.sh are the same"
if [[ "$fallback_version" != "$run_reframe_testsuite_version" ]]; then
echo "Version $fallback_version not equal to $run_reframe_testsuite_version"
exit 1
else
echo "... yes!"
fi
echo "Testing if fallback version and most recent version tag are the same"
if [[ "$fallback_version" != "$most_recent_version" ]]; then
echo "Version $fallback_version not equal to $most_recent_version"
exit 1
else
echo "... yes!"
fi
86 changes: 86 additions & 0 deletions .github/workflows/pip_install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0
Expand All @@ -34,12 +35,18 @@ jobs:
- name: Install EESSI test suite with 'pip install'
run: |
# Make it easier to figure out CI issues in case of CI failures related to SCM versioning
export SETUPTOOLS_SCM_DEBUG=1
# install from source distribution tarball, to test release as published on PyPI
rm -rf dist
echo "Running python setup.py sdist"
python setup.py sdist
ls dist
echo "Running python -m pip install --user dist/eessi*.tar.gz"
python -m pip install --user dist/eessi*.tar.gz
echo "Checking contents of .local"
find $HOME/.local
# make sure we are not in the source directory
Expand All @@ -49,5 +56,84 @@ jobs:
python -m pip --version
python -c 'import setuptools; print("setuptools", setuptools.__version__)'
echo "Checking if file 'eessi/testsuite/_version.py' was generated by setuptools_scm":
cat $HOME/.local/lib/python${{ matrix.python-version}}/site-packages/eessi/testsuite/_version.py
echo "Checking if version can be imported directly from the version file"
if [[ "${{ matrix.python-version }}" == "3.6" ]]; then
versionfile_version=$(python -c 'from eessi.testsuite._version import version; print(version)')
else
versionfile_version=$(python -c 'from eessi.testsuite._version import __version__; print(__version__)')
fi
echo "Version from version file: $versionfile_version"
echo "Checking if we can import the __version__ from eessi.testsuite"
testsuite_version=$(python -c 'import eessi.testsuite; print(eessi.testsuite.__version__)')
echo "Version imported from eessi.testsuite: $testsuite_version"
echo "Checking if the version imported from eessi.testsuite matches that from the version file ..."
if [[ "$versionfile_version" != "$testsuite_version" ]]; then
echo "Version $versionfile_version not equal to $testsuite_version"
exit 1
else
echo "... yes!"
fi
echo "Checking if we can import eessi.testsuite.utils"
python -c 'import eessi.testsuite.utils'
echo "Checking if we can import eessi.testsuite.tests.apps"
python -c 'import eessi.testsuite.tests.apps'
- name: Install EESSI test suite with 'pip install git+https'
run: |
# Get version from the installation in the previous step
testsuite_version=$(python -c 'import eessi.testsuite; print(eessi.testsuite.__version__)')
# Cleanup installation from previous step
echo "Uninstalling testsuite for next step"
python -m pip uninstall -y eessi-testsuite
pip install --user "git+$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git@$GITHUB_SHA"
echo "Checking contents of .local"
find $HOME/.local
echo "Checking if file 'eessi/testsuite/_version.py' was generated by setuptools_scm":
cat $HOME/.local/lib/python${{ matrix.python-version}}/site-packages/eessi/testsuite/_version.py
echo "Checking if version can be imported directly from the version file"
if [[ "${{ matrix.python-version }}" == "3.6" ]]; then
githttps_versionfile_version=$(python -c 'from eessi.testsuite._version import version; print(version)')
else
githttps_versionfile_version=$(python -c 'from eessi.testsuite._version import __version__; print(__version__)')
fi
echo "Version from version file: $githttps_versionfile_version"
echo "Checking if we can import the __version__ from eessi.testsuite"
githttps_testsuite_version=$(python -c 'import eessi.testsuite; print(eessi.testsuite.__version__)')
echo "Version imported from eessi.testsuite: $githttps_testsuite_version"
echo "Checking if the version imported from eessi.testsuite matches that from the version file ..."
if [[ "$githttps_versionfile_version" != "$githttps_testsuite_version" ]]; then
echo "Version $githttps_versionfile_version not equal to $githttps_testsuite_version"
exit 1
else
echo "... yes!"
fi
echo "Checking if the version import from a regular pip install and the git+https based install are the same ..."
if [[ "$githttps_testsuite_version" != "$testsuite_version" ]]; then
echo "Version $githttps_testsuite_version not equal to $testsuite_version"
exit 1
else
echo "... yes!"
fi
echo "Checking if we can import eessi.testsuite.utils"
python -c 'import eessi.testsuite.utils'
echo "Checking if we can import eessi.testsuite.tests.apps"
python -c 'import eessi.testsuite.tests.apps'
83 changes: 83 additions & 0 deletions eessi/testsuite/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# WARNING: this file is imported in setup.py
# To make sure this works, we should avoid using imports other than from the Python standard library

try:
# If this is an installed package, setuptools_scm will have written the _version.py file in the current directory
from ._version import __version__
except ImportError:
try:
# Setuptools_scm 4.1.2 (compatible with setuptools 39.2.0) write version instead of __version__
# This can be removed once we no longer care about python 3.6 with setuptools 39.2.0
from ._version import version
__version__ = version
except ImportError:
# Fallback for when the package is not installed, but git cloned. Note that this requires setuptools_scm to be
# available as a runtime dependency
# The advantage here is that it will generate development versions if not on a tagged release version
try:
from setuptools_scm import get_version
# Using a relative path for relative_to doesn't work, because it will be relative to the current working
# directory (which could be anywhere)
# __file__ is the location of this init file (a full path), and this gives us a predictable path to the root
# (namely: two levels up). Note that if we ever move this __init__ file relative to the root of the git
# tree, we'll need to adjust this
__version__ = get_version(root='../..', relative_to=__file__)
except (ImportError, LookupError):
# If running from a tarball (e.g. release tarball) downloaded from github, we will not have the .git
# folder available. Thus, setuptools_scm cannot determine the version in any way. Thus, use the
# fallback_version from the pyproject.toml file (which doesn't exist when this is installed as a package,
# but SHOULD exist when this is run from a downloaded tarball from git)

# Pyproject.toml should be two levels up from this file
import os.path
pyproject_toml = "%s/../../pyproject.toml" % os.path.dirname(__file__)

# Variables to track if we're in the right section and to store the fallback_version
in_setuptools_scm_section = False
fallback_version = None

file = None
try:
file = open(pyproject_toml, 'r')
# Open the file and parse it manually
fallback_version = None
with file:
for line in file:
stripped_line = line.strip()

# Check if we're entering the [tool.setuptools_scm] section
if stripped_line == "[tool.setuptools_scm]":
in_setuptools_scm_section = True
elif stripped_line.startswith("[") and in_setuptools_scm_section:
# We've reached a new section, so stop searching
break

# If we're in the right section, look for the fallback_version key
if in_setuptools_scm_section and stripped_line.startswith("fallback_version"):
# Extract the value after the '=' sign and strip any surrounding quotes or whitespace
fallback_version = stripped_line.split('=', 1)[1].strip().strip('"').strip("'")
break
# Account for the possibility that we failed to extract the fallback_version field from pyproject.toml
if fallback_version:
__version__ = fallback_version
else:
msg = "fallback_version not found in file %s" % pyproject_toml
msg += " when trying the get the EESSI test suite version. This should never happen."
msg += " Please report an issue on Github, including information on how you installed"
msg += " the EESSI test suite."
print(msg)
except FileNotFoundError:
msg = "File %s not found when trying to extract the EESSI test suite version from" % pyproject_toml
msg += " pyproject.toml. This should never happen. Please report an issue on GitHub,"
msg += " including information on how you installed the EESSI test suite."
print(msg)
except Exception as e:
print("When trying to open file %s, an exception was raised: %s." % (pyproject_toml, e))

# One of the above three methods to get __version__ defined SHOULD work in any situation.
# It's considered a bug you reach this point without having a __version__ set
if not __version__:
msg = "__version__ should have been defined by now, but it is not."
msg += " This is considered a bug, please report it in an issue on Github for the"
msg += " EESSI test suite."
raise ValueError(msg)
Loading

0 comments on commit 82512b1

Please sign in to comment.