From 641ebfee4cc982fd187eddca03578e5dc9e2602d Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 16 Nov 2023 10:11:58 +0100 Subject: [PATCH 01/12] scripts/python/module/Makefile.am: allow "make clean dist" to do a sane thing Signed-off-by: Jim Klimov --- scripts/python/module/Makefile.am | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/python/module/Makefile.am b/scripts/python/module/Makefile.am index 8e03eab6a2..dec940ac60 100644 --- a/scripts/python/module/Makefile.am +++ b/scripts/python/module/Makefile.am @@ -11,13 +11,18 @@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ PYTHON = @PYTHON@ GENERATED_DIST = dist build *.egg-info -GENERATED_SRC = src README.txt +GENERATED_SRC = src README.txt LICENSE-GPL3 + +# These are normally generated by a NUT build, but if we want to iterate +# specifically PyNUTClient packaging - `make clean dist` should do it here: +GENERATED_PY = test_nutclient.py PyNUT.py setup.py $(GENERATED_DIST): .pypi-dist clean-local: rm -rf $(GENERATED_SRC) $(GENERATED_DIST) - rm -f .pypi-src .pypi-dist LICENSE-GPL3 + rm -f .pypi-src .pypi-dist + rm -f $(GENERATED_PY) MAINTAINERCLEANFILES = Makefile.in .dirstamp .pypi-tools* From ccf4962fa656ad593ad66bde5f2bcc2ff99d236a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 16 Nov 2023 10:20:48 +0100 Subject: [PATCH 02/12] scripts/python/module/Makefile.am: clean the many .pypi-dist* touch-files we have now Signed-off-by: Jim Klimov --- scripts/python/module/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/python/module/Makefile.am b/scripts/python/module/Makefile.am index dec940ac60..7b9ef38a06 100644 --- a/scripts/python/module/Makefile.am +++ b/scripts/python/module/Makefile.am @@ -19,9 +19,11 @@ GENERATED_PY = test_nutclient.py PyNUT.py setup.py $(GENERATED_DIST): .pypi-dist +# NOTE: We only clean .pypi-tools* in MAINTAINERCLEANFILES to avoid regular +# re-detection of the probably unchanging environment! clean-local: rm -rf $(GENERATED_SRC) $(GENERATED_DIST) - rm -f .pypi-src .pypi-dist + rm -f .pypi-src .pypi-dist* rm -f $(GENERATED_PY) MAINTAINERCLEANFILES = Makefile.in .dirstamp .pypi-tools* From dc787693361491ff2fcb24c4b8c83f68ea05fc3d Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 16 Nov 2023 10:33:17 +0100 Subject: [PATCH 03/12] scripts/python/module/Makefile.am: create the PyNUTClient/src directory for better module naming Signed-off-by: Jim Klimov --- scripts/python/module/Makefile.am | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/python/module/Makefile.am b/scripts/python/module/Makefile.am index 7b9ef38a06..7b37eced54 100644 --- a/scripts/python/module/Makefile.am +++ b/scripts/python/module/Makefile.am @@ -5,13 +5,13 @@ # Non-maintainers can at most generate the source layout for python setuptools # (having only shell scripting as a prerequisite suffices for that) -all: src +all: PyNUTClient NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ PYTHON = @PYTHON@ GENERATED_DIST = dist build *.egg-info -GENERATED_SRC = src README.txt LICENSE-GPL3 +GENERATED_SRC = PyNUTClient README.txt LICENSE-GPL3 # These are normally generated by a NUT build, but if we want to iterate # specifically PyNUTClient packaging - `make clean dist` should do it here: @@ -28,7 +28,7 @@ clean-local: MAINTAINERCLEANFILES = Makefile.in .dirstamp .pypi-tools* -src: .pypi-src +PyNUTClient: .pypi-src # Tagged releases should only have three blocks of digits separated by dots upload publish: @@ -42,7 +42,7 @@ upload publish: .pypi-src: test_nutclient.py.in PyNUT.py.in setup.py.in README.adoc Makefile $(top_srcdir)/LICENSE-GPL3 @echo " PYPI Generate PyPI module source" @rm -rf $(GENERATED_SRC) "$@" - @mkdir src + @mkdir -p PyNUTClient/src @for S in "$(srcdir)"/*.py.in ; do \ B="`basename "$${S}" .in`" ; \ if test x"$${B}" = xsetup.py ; then \ @@ -52,15 +52,15 @@ upload publish: continue; \ fi; \ if test -s "$${B}" ; then \ - cp -pf "$${B}" src/ || exit ; \ + cp -pf "$${B}" PyNUTClient/src/ || exit ; \ continue; \ fi ; \ - sed -e "s,[@]PYTHON[@],@PYTHON@," < "$(srcdir)/$${B}.in" > "src/$${B}" || exit ; \ - if test -x "$(srcdir)/$${B}.in" ; then chmod +x "src/$${B}"; fi ; \ + sed -e "s,[@]PYTHON[@],@PYTHON@," < "$(srcdir)/$${B}.in" > "PyNUTClient/src/$${B}" || exit ; \ + if test -x "$(srcdir)/$${B}.in" ; then chmod +x "PyNUTClient/src/$${B}"; fi ; \ done ; \ cp -pf "$(srcdir)/README.adoc" README.txt || exit ; \ cp -pf "$(top_srcdir)/LICENSE-GPL3" . || exit ; \ - echo "from . import PyNUT" > src/__init__.py || exit + echo "from . import PyNUT" > PyNUTClient/src/__init__.py || exit @touch "$@" .pypi-tools-python: From 075d5c204065aebabe8268d06daa015af12e4b69 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 16 Nov 2023 10:40:37 +0100 Subject: [PATCH 04/12] scripts/python/module/setup.py.in: clean up formatting Signed-off-by: Jim Klimov --- scripts/python/module/setup.py.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/python/module/setup.py.in b/scripts/python/module/setup.py.in index d74184ae4f..9270652669 100644 --- a/scripts/python/module/setup.py.in +++ b/scripts/python/module/setup.py.in @@ -18,13 +18,13 @@ setup( name = "PyNUTClient", version = '@NUT_SOURCE_GITREV_NUMERIC@', author = "The Network UPS Tools project", - license_files = ('LICENSE-GPL3',), + license_files = ('LICENSE-GPL3',), author_email = "jimklimov+nut@gmail.com", description = "Python client bindings for NUT", url = "https://github.com/networkupstools/nut/tree/master/scripts/python/module", long_description_content_type = "text/plain", # NOTE: No asciidoc so far, see https://packaging.python.org/en/latest/specifications/core-metadata/ long_description = long_description, - packages = find_packages(), + packages = find_packages(), # install_requires = ['telnetlib'], # NOTE: telnetlib.py is part of Python core for tested 2.x and 3.x versions, not something 'pip' can download keywords = ['pypi', 'cicd', 'python'], classifiers = [ From 7080355f4a8644d695ef2c5c1c2a5462d2e282b2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 16 Nov 2023 10:40:55 +0100 Subject: [PATCH 05/12] scripts/python/module/setup.py.in: constrain lowest known compatible python version Signed-off-by: Jim Klimov --- scripts/python/module/setup.py.in | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/python/module/setup.py.in b/scripts/python/module/setup.py.in index 9270652669..c4e84499c1 100644 --- a/scripts/python/module/setup.py.in +++ b/scripts/python/module/setup.py.in @@ -25,6 +25,7 @@ setup( long_description_content_type = "text/plain", # NOTE: No asciidoc so far, see https://packaging.python.org/en/latest/specifications/core-metadata/ long_description = long_description, packages = find_packages(), + python_requires = '>=2.6', # install_requires = ['telnetlib'], # NOTE: telnetlib.py is part of Python core for tested 2.x and 3.x versions, not something 'pip' can download keywords = ['pypi', 'cicd', 'python'], classifiers = [ From 2d91a9205ac58b21c17daeb122e5496c01776a8f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 16 Nov 2023 10:42:54 +0100 Subject: [PATCH 06/12] scripts/python/module/setup.py.in: update "keywords" to refer to NUT Signed-off-by: Jim Klimov --- scripts/python/module/setup.py.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/python/module/setup.py.in b/scripts/python/module/setup.py.in index c4e84499c1..c5bb3d2a3f 100644 --- a/scripts/python/module/setup.py.in +++ b/scripts/python/module/setup.py.in @@ -27,7 +27,7 @@ setup( packages = find_packages(), python_requires = '>=2.6', # install_requires = ['telnetlib'], # NOTE: telnetlib.py is part of Python core for tested 2.x and 3.x versions, not something 'pip' can download - keywords = ['pypi', 'cicd', 'python'], + keywords = ['pypi', 'cicd', 'python', 'nut', 'Network UPS Tools'], classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", From 7b237a5dc9732ea7f262082b820526082f56c855 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Nov 2023 14:07:46 +0100 Subject: [PATCH 07/12] scripts/python/module: add Python testing framework handling (tox.ini etc) [#2186] Signed-off-by: Jim Klimov --- scripts/python/module/.gitignore | 1 + scripts/python/module/Makefile.am | 8 ++++++++ scripts/python/module/tox.ini | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 scripts/python/module/tox.ini diff --git a/scripts/python/module/.gitignore b/scripts/python/module/.gitignore index 6073a68036..bb543d29fa 100644 --- a/scripts/python/module/.gitignore +++ b/scripts/python/module/.gitignore @@ -5,6 +5,7 @@ /build /dist /src +/.tox /README.txt /.pypi-* /LICENSE-GPL3 diff --git a/scripts/python/module/Makefile.am b/scripts/python/module/Makefile.am index 7b37eced54..1fd2e74c80 100644 --- a/scripts/python/module/Makefile.am +++ b/scripts/python/module/Makefile.am @@ -7,6 +7,8 @@ # (having only shell scripting as a prerequisite suffices for that) all: PyNUTClient +EXTRA_DIST = tox.ini + NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ PYTHON = @PYTHON@ @@ -26,6 +28,12 @@ clean-local: rm -f .pypi-src .pypi-dist* rm -f $(GENERATED_PY) +# Python test envs take a while to populate, so maybe better not clean +# them too enthusiastically. Can revise (move to "clean-local") later, +# if this choice proves a problem. +distclean-local: + rm -rf .tox + MAINTAINERCLEANFILES = Makefile.in .dirstamp .pypi-tools* PyNUTClient: .pypi-src diff --git a/scripts/python/module/tox.ini b/scripts/python/module/tox.ini new file mode 100644 index 0000000000..890bb60f23 --- /dev/null +++ b/scripts/python/module/tox.ini @@ -0,0 +1,23 @@ +# Configuration for Python test environment manager +# https://tox.wiki/en/latest/user_guide.html +# +# Note that to run `test_nutclient.py` you must prepare a running NUT data +# server (upsd) with a connected driver. You can use a dummy-ups driver for +# that, see e.g. NUT tests/NIT/nit.sh for how the test beds are prepared. +# Further you may need to export `NUT_HOST` and `NUT_PORT` (if not default), +# and a `NUT_USER` and `NUT_PASS` for tests with logged-in session behaviors. +# Then just run `tox` (may have to `pip install tox` first though). + +[tox] +envlist = + py2{6,7} + py3{5,5,6,7,8,9,10,11,12,13} + +[testenv] +setenv = + PYTHONPATH = {toxinidir}:{toxinidir}/PyNUTClient:{toxinidir}/PyNUTClient/src + +commands = + pip install -U pip + python PyNUTClient/src/test_nutclient.py + #py.test --basetemp={envtmpdir} From 1145b95abedc8f1c5c0de67ddb852df63178ef71 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Nov 2023 14:38:46 +0100 Subject: [PATCH 08/12] scripts/python/module/Makefile.am: add "py-in" and "redist" targets for manual iterations Signed-off-by: Jim Klimov --- scripts/python/module/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/python/module/Makefile.am b/scripts/python/module/Makefile.am index 1fd2e74c80..b81298e8c6 100644 --- a/scripts/python/module/Makefile.am +++ b/scripts/python/module/Makefile.am @@ -19,6 +19,11 @@ GENERATED_SRC = PyNUTClient README.txt LICENSE-GPL3 # specifically PyNUTClient packaging - `make clean dist` should do it here: GENERATED_PY = test_nutclient.py PyNUT.py setup.py +# (Re-)generate files normally made by `configure` from .in templates +# No touch-files here, intended for manual use in developer iterations +py-in: $(GENERATED_PY) +redist: clean py-in dist + $(GENERATED_DIST): .pypi-dist # NOTE: We only clean .pypi-tools* in MAINTAINERCLEANFILES to avoid regular From 869caa8067baf4cdaf2905111e2e4ec48a6bb070 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Nov 2023 16:28:19 +0100 Subject: [PATCH 09/12] Py: try to beat sense into packaging all the files Signed-off-by: Jim Klimov --- scripts/python/module/Makefile.am | 10 +++++----- scripts/python/module/setup.py.in | 4 ++++ scripts/python/module/tox.ini | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/scripts/python/module/Makefile.am b/scripts/python/module/Makefile.am index b81298e8c6..d8d5843d32 100644 --- a/scripts/python/module/Makefile.am +++ b/scripts/python/module/Makefile.am @@ -55,7 +55,7 @@ upload publish: .pypi-src: test_nutclient.py.in PyNUT.py.in setup.py.in README.adoc Makefile $(top_srcdir)/LICENSE-GPL3 @echo " PYPI Generate PyPI module source" @rm -rf $(GENERATED_SRC) "$@" - @mkdir -p PyNUTClient/src + @mkdir -p PyNUTClient @for S in "$(srcdir)"/*.py.in ; do \ B="`basename "$${S}" .in`" ; \ if test x"$${B}" = xsetup.py ; then \ @@ -65,15 +65,15 @@ upload publish: continue; \ fi; \ if test -s "$${B}" ; then \ - cp -pf "$${B}" PyNUTClient/src/ || exit ; \ + cp -pf "$${B}" PyNUTClient/ || exit ; \ continue; \ fi ; \ - sed -e "s,[@]PYTHON[@],@PYTHON@," < "$(srcdir)/$${B}.in" > "PyNUTClient/src/$${B}" || exit ; \ - if test -x "$(srcdir)/$${B}.in" ; then chmod +x "PyNUTClient/src/$${B}"; fi ; \ + sed -e "s,[@]PYTHON[@],@PYTHON@," < "$(srcdir)/$${B}.in" > "PyNUTClient/$${B}" || exit ; \ + if test -x "$(srcdir)/$${B}.in" ; then chmod +x "PyNUTClient/$${B}"; fi ; \ done ; \ cp -pf "$(srcdir)/README.adoc" README.txt || exit ; \ cp -pf "$(top_srcdir)/LICENSE-GPL3" . || exit ; \ - echo "from . import PyNUT" > PyNUTClient/src/__init__.py || exit + echo "from . import PyNUT" > PyNUTClient/__init__.py || exit @touch "$@" .pypi-tools-python: diff --git a/scripts/python/module/setup.py.in b/scripts/python/module/setup.py.in index c5bb3d2a3f..c3a8de24be 100644 --- a/scripts/python/module/setup.py.in +++ b/scripts/python/module/setup.py.in @@ -25,6 +25,10 @@ setup( long_description_content_type = "text/plain", # NOTE: No asciidoc so far, see https://packaging.python.org/en/latest/specifications/core-metadata/ long_description = long_description, packages = find_packages(), + #py_modules = ['PyNUT'], + package_dir = {'PyNUT': 'PyNUTClient'}, + data_files = [('', ['tox.ini'])], + #scripts = ['PyNUTClient/test_nutclient.py', 'PyNUTClient/__init__.py'], python_requires = '>=2.6', # install_requires = ['telnetlib'], # NOTE: telnetlib.py is part of Python core for tested 2.x and 3.x versions, not something 'pip' can download keywords = ['pypi', 'cicd', 'python', 'nut', 'Network UPS Tools'], diff --git a/scripts/python/module/tox.ini b/scripts/python/module/tox.ini index 890bb60f23..dfaf04b8d9 100644 --- a/scripts/python/module/tox.ini +++ b/scripts/python/module/tox.ini @@ -15,9 +15,9 @@ envlist = [testenv] setenv = - PYTHONPATH = {toxinidir}:{toxinidir}/PyNUTClient:{toxinidir}/PyNUTClient/src + PYTHONPATH = {toxinidir}:{toxinidir}/src/PyNUTClient commands = pip install -U pip - python PyNUTClient/src/test_nutclient.py + python src/PyNUTClient/test_nutclient.py #py.test --basetemp={envtmpdir} From a81389432c371bf013dc2855d31e9f208c318fb8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Nov 2023 23:16:05 +0100 Subject: [PATCH 10/12] .github/workflows/PyNUTClient.yml: fix typo determining TAG_NAME Signed-off-by: Jim Klimov --- .github/workflows/PyNUTClient.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/PyNUTClient.yml b/.github/workflows/PyNUTClient.yml index e438421bd0..5af313208e 100644 --- a/.github/workflows/PyNUTClient.yml +++ b/.github/workflows/PyNUTClient.yml @@ -38,7 +38,7 @@ jobs: run: >- TAG_NAME="$(echo $GITHUB_REF | cut -d / -f 3)" ; if [ x"$TAG_NAME" = xmaster ]; then - TAG_NAME="$(git describe --tags --match 'v[0-9]*.[0-9]*.[0-9]' --exclude '*-signed' --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' 2>/dev/null || git describe --tags --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' --exclude '*Windows*' --exclude '*IPM*' 2>/dev/null ) | sed -e 's/^v\([0-9]\)/\1/' -e 's,^.*/,,')" \ + TAG_NAME="$(git describe --tags --match 'v[0-9]*.[0-9]*.[0-9]' --exclude '*-signed' --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' 2>/dev/null || git describe --tags --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' --exclude '*Windows*' --exclude '*IPM*' 2>/dev/null | sed -e 's/^v\([0-9]\)/\1/' -e 's,^.*/,,')" \ && test -n "${TAG_NAME}" \ || TAG_NAME="2.8.1-`TZ=UTC date +%s`" ; fi ; From 80c2f695ea2c5a1a0af9795f1b207a4246d1f803 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Nov 2023 23:24:17 +0100 Subject: [PATCH 11/12] scripts/python/module/tox.ini: update pip as a "commands_pre" action [#2186] Signed-off-by: Jim Klimov --- scripts/python/module/tox.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/python/module/tox.ini b/scripts/python/module/tox.ini index dfaf04b8d9..ee5c1755a8 100644 --- a/scripts/python/module/tox.ini +++ b/scripts/python/module/tox.ini @@ -17,7 +17,9 @@ envlist = setenv = PYTHONPATH = {toxinidir}:{toxinidir}/src/PyNUTClient +commands_pre = + python -m pip install -U pip + commands = - pip install -U pip python src/PyNUTClient/test_nutclient.py #py.test --basetemp={envtmpdir} From 112581d67968f83cd7d1f8d24d91e457cb1a2e86 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Nov 2023 23:41:09 +0100 Subject: [PATCH 12/12] .github/workflows/PyNUTClient.yml: convert to use scripts/python/module/Makefile.am directly, to avoid discrepancies in two logic impementations Signed-off-by: Jim Klimov --- .github/workflows/PyNUTClient.yml | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/.github/workflows/PyNUTClient.yml b/.github/workflows/PyNUTClient.yml index 5af313208e..b523064259 100644 --- a/.github/workflows/PyNUTClient.yml +++ b/.github/workflows/PyNUTClient.yml @@ -27,10 +27,10 @@ jobs: uses: actions/setup-python@v3 with: python-version: '3.10' - - name: Install pypa/setuptools + - name: Extract python interpreter path name + id: pythoncmd run: >- - python -m - pip install wheel build + echo "PYTHON=$(command -v python)" >> $GITHUB_OUTPUT - name: Extract tag name id: tag # Note: this is all a single shell line in the end, @@ -44,26 +44,20 @@ jobs: fi ; TAG_NAME="$(echo "$TAG_NAME" | sed -e 's/^v//' -e 's/-g.*$//' -e 's/-/./g')" ; echo "TAG_NAME=$TAG_NAME" >> $GITHUB_OUTPUT + - name: Install pypa/setuptools + run: >- + ${{ steps.pythoncmd.outputs.PYTHON }} -m + ${{ steps.pythoncmd.outputs.PYTHON }} -m pip install wheel build - name: Update version in setup.py run: >- if [ ! -s scripts/python/module/setup.py ] ; then sed -e "s/@NUT_SOURCE_GITREV_NUMERIC@/${{ steps.tag.outputs.TAG_NAME }}/g" < scripts/python/module/setup.py.in > scripts/python/module/setup.py ; fi - - name: Prepare source layout + - name: Prepare source layout and Build a binary wheel run: >- set -e ; cd scripts/python/module ; - mkdir src ; - for F in *.py.in ; do sed -e "s,@PYTHON@,$(command -v python)," < "$F" > "src/`basename "$F" .in`" ; done ; - cp README.adoc README.txt ; - cp ../../../LICENSE-GPL3 . ; - chmod +x src/test*.py ; - - name: Build a binary wheel - run: >- - cd scripts/python/module ; - python -m build --skip-dependency-check --no-isolation - || { rm -rf build dist *egg* ; python setup.py sdist bdist_wheel ; } - || { rm -rf build dist *egg* ; python -m pip wheel . -w dist --no-deps ; } ; + make -f Makefile.am clean-local dist NUT_SOURCE_GITREV_NUMERIC="${{ steps.tag.outputs.TAG_NAME }}" PYTHON="${{ steps.pythoncmd.outputs.PYTHON }}" top_srcdir="../../.." srcdir="." builddir="." ; find . -ls - name: Publish master distribution 📦 to Test PyPI # https://github.com/pypa/gh-action-pypi-publish