diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 000000000..27e9889c4 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,44 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python application + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["pypy3.10", "3.9", "3.10", "3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Display Python version + run: python -c "import sys; print(sys.version)" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index 9cb959844..67e4de451 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ # must mock PyQt in order to get autodoc import running MOCK_MODULES = ['numpy', 'scipy', 'qtpy', 'pyqtgraph', 'pandas', - 'asyncio', 'quamash', 'scipy.signal', 'scipy.fftpack', + 'asyncio', 'qasync', 'scipy.signal', 'scipy.fftpack', 'paramiko', 'scp'] sys.modules.update((mod_name, MagicMock()) for mod_name in MOCK_MODULES) diff --git a/docs/source/developer_guide/api/asynchronous/index.rst b/docs/source/developer_guide/api/asynchronous/index.rst index 1503c01ef..56e0a5411 100644 --- a/docs/source/developer_guide/api/asynchronous/index.rst +++ b/docs/source/developer_guide/api/asynchronous/index.rst @@ -19,10 +19,10 @@ function). Let's see that on an example: %pylab qt # in a notebook, we need the qt event loop to run in the background import asyncio import scipy.fftpack - import quamash # quamash allows to use the asyncio syntax of python 3 with the Qt event loop. Not sure how mainstream the library is... + import qasync # qasync allows to use the asyncio syntax of python 3 with the Qt event loop. Not sure how mainstream the library is... from PyQt4 import QtCore, QtGui import asyncio - loop = quamash.QEventLoop() + loop = qasync.QEventLoop() asyncio.set_event_loop(loop) # set the qt event loop as the loop to be used by asyncio @@ -58,12 +58,12 @@ practice, the code execution is probably extremely similar) %pylab qt import asyncio import scipy.fftpack - import quamash + import qasync from PyQt4 import QtCore, QtGui APP = QtGui.QApplication.instance() import asyncio from promise import Promise - loop = quamash.QEventLoop() + loop = qasync.QEventLoop() asyncio.set_event_loop(loop) @@ -187,10 +187,10 @@ would easily do the trick: %pylab qt import asyncio import scipy.fftpack - import quamash + import qasync from PyQt4 import QtCore, QtGui import asyncio - loop = quamash.QEventLoop() + loop = qasync.QEventLoop() asyncio.set_event_loop(loop) diff --git a/.travis.yml b/old_CI_config_files/.travis.yml old mode 100755 new mode 100644 similarity index 100% rename from .travis.yml rename to old_CI_config_files/.travis.yml diff --git a/Dockerfile b/old_CI_config_files/Dockerfile similarity index 100% rename from Dockerfile rename to old_CI_config_files/Dockerfile diff --git a/Jenkinsfile b/old_CI_config_files/Jenkinsfile similarity index 98% rename from Jenkinsfile rename to old_CI_config_files/Jenkinsfile index 9c60d714b..acb6c61fc 100644 --- a/Jenkinsfile +++ b/old_CI_config_files/Jenkinsfile @@ -1,175 +1,175 @@ -#!groovy - - - -def getRepoURL() { - sh "git config --get remote.origin.url > .git/remote-url" - return readFile(".git/remote-url").trim() -} - -def getCommitSha() { - sh "git rev-parse HEAD > .git/current-commit" - return readFile(".git/current-commit").trim() -} - -void setBuildStatus(String message, String state) { - step([ - $class: "GitHubCommitStatusSetter", - reposSource: [$class: "ManuallyEnteredRepositorySource", url: getRepoURL()], - contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/build-status"], - errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]], - statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ] - ]); -} - - -pipeline { - triggers { pollSCM('*/1 * * * *') } - - options { - // skipDefaultCheckout(true) // rather do the checkout in all stages - // Keep the 10 most recent builds - buildDiscarder(logRotator(numToKeepStr: '10')) - timestamps() - } - - - environment { - REDPITAYA_HOSTNAME = "192.168.178.26" - //REDPITAYA_HOSTNAME = "rp-f03f3a" - //REDPITAYA_HOSTNAME = "nobody.justdied.com" - DOCKER_ARGS = '-u root -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0 --net=host' - //NOSETESTS_COMMAND = 'nosetests pyrpl/test/test_ipython_notebook/test_ipython_kernel.py' - NOSETESTS_COMMAND = 'nosetests' - PYPI = credentials('f63335ce-493d-4caf-8ebe-d7e2629f79f3') - REDPITAYA = credentials('2bf38f88-833a-4624-9682-3a6f0a145d30') - REDPITAYA_USER = "$REDPITAYA_USR" - REDPITAYA_PASSWORD = "$REDPITAYA_PSW" - - } - - agent any - - stages { - stage('Notify github that a build was started') { - agent any - steps { setBuildStatus("Jenkins build started...", "PENDING") }} - stage('Unit tests') { parallel { - stage('Python 3.7') { - agent { dockerfile { args "$DOCKER_ARGS" - additionalBuildArgs '--build-arg PYTHON_VERSION=3.7' }} - steps { lock('redpitaya') { - sh ''' which python - python -V - echo $PYTHON_VERSION - conda list - # use a custom global configfile adapted to the hardware for unit tests - cp ./jenkins_global_config.yml ./pyrpl/config/global_config.yml - python setup.py install - ''' - sh "$NOSETESTS_COMMAND" }} - post { always { junit allowEmptyResults: true, testResults: 'unit_test_results.xml' }}} - stage('Python 3.6') { - agent { dockerfile { args "$DOCKER_ARGS" - additionalBuildArgs '--build-arg PYTHON_VERSION=3.6' }} - steps { lock('redpitaya') { - sh ''' which python - python -V - echo $PYTHON_VERSION - conda list - # use a custom global configfile adapted to the hardware for unit tests - cp ./jenkins_global_config.yml ./pyrpl/config/global_config.yml - python setup.py install - ''' - sh "$NOSETESTS_COMMAND"}} - post { always { junit allowEmptyResults: true, testResults: 'unit_test_results.xml' }}} - /*stage('Python 3.5') { - agent { dockerfile { args "$DOCKER_ARGS" - additionalBuildArgs '--build-arg PYTHON_VERSION=3.5' }} - steps { - sh ''' which python - python -V - echo $PYTHON_VERSION - conda list - # use a custom global configfile adapted to the hardware for unit tests - cp ./jenkins_global_config.yml ./pyrpl/config/global_config.yml - python setup.py install - ''' - sh "$NOSETESTS_COMMAND"} - post { always { junit allowEmptyResults: true, testResults: 'unit_test_results.xml' }}}*/ - stage('Python 2.7') { - agent { dockerfile { args "$DOCKER_ARGS" - additionalBuildArgs '--build-arg PYTHON_VERSION=2.7' }} - steps { lock('redpitaya') { - sh ''' which python - python -V - echo $PYTHON_VERSION - conda list - # use a custom global configfile adapted to the hardware for unit tests - cp ./jenkins_global_config.yml ./pyrpl/config/global_config.yml - python setup.py install - ''' - sh "$NOSETESTS_COMMAND"}} - post { always { junit allowEmptyResults: true, testResults: 'unit_test_results.xml' }}} - stage('Linux binary') { - agent { dockerfile { args '-u root -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0 --net=host' - additionalBuildArgs '--build-arg PYTHON_VERSION=3.7' }} - steps { lock('fake_redpitaya') { - sh ''' apt-get install psmisc - python setup.py install - pip install https://github.com/lneuhaus/pyinstaller/tarball/develop - pyinstaller pyrpl.spec - mv dist/pyrpl ./pyrpl-linux-develop - python .deploy_to_sourceforge.py pyrpl-linux-develop - chmod 755 pyrpl-linux-develop - (./pyrpl-linux-develop config=test_linux hostname=_FAKE_ &) - PYRPL_PID=$! - sleep 30 - killall -9 pyrpl-linux-develop - ''' - //sh 'python .deploy_to_sourceforge.py pyrpl-linux-develop' - }} - post { always { archiveArtifacts allowEmptyArchive: true, artifacts: 'pyrpl-linux-develop', fingerprint: true }}} - stage('pip wheel') { - agent { dockerfile { args '-u root -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0 --net=host' - additionalBuildArgs '--build-arg PYTHON_VERSION=3.7' }} - steps { lock('fake_redpitaya') { - sh ''' python setup.py install - # convert readme file to rst for PyPI - conda install pandoc - pandoc --from=markdown --to=rst --output=README.rst README.md - # make distributions for PyPI - python setup.py sdist - python setup.py bdist_wheel --universal - # upload to PyPI - # twine upload dist/**/*.* - '''}} - post { always { archiveArtifacts allowEmptyArchive: true, artifacts: 'dist/**/*.*', fingerprint: true}}} - }} - stage('Deploy') { - agent { dockerfile { args '-u root -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0 --net=host' - additionalBuildArgs '--build-arg PYTHON_VERSION=3.7' }} - when { - expression { currentBuild.result == null || currentBuild.result == 'SUCCESS'}} - steps { - sh ''' python setup.py install - '''}} - } - post { - failure { - emailext ( - attachLog: true, - subject: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'", - body: """
FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]':
-Check console output at ${env.JOB_NAME} [${env.BUILD_NUMBER}]
""", - compressLog: false, - recipientProviders: [requestor(), developers(), brokenTestsSuspects(), brokenBuildSuspects(), upstreamDevelopers(), culprits()], - replyTo: 'pyrpl.readthedocs.io@gmail.com', - to: 'pyrpl.readthedocs.io@gmail.com') - setBuildStatus("Build failed!", "FAILURE") - } - success { setBuildStatus("Build successful!", "SUCCESS") } - unstable { setBuildStatus("Build erroneous!", "ERROR") } - } -} - +#!groovy + + + +def getRepoURL() { + sh "git config --get remote.origin.url > .git/remote-url" + return readFile(".git/remote-url").trim() +} + +def getCommitSha() { + sh "git rev-parse HEAD > .git/current-commit" + return readFile(".git/current-commit").trim() +} + +void setBuildStatus(String message, String state) { + step([ + $class: "GitHubCommitStatusSetter", + reposSource: [$class: "ManuallyEnteredRepositorySource", url: getRepoURL()], + contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/build-status"], + errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]], + statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ] + ]); +} + + +pipeline { + triggers { pollSCM('*/1 * * * *') } + + options { + // skipDefaultCheckout(true) // rather do the checkout in all stages + // Keep the 10 most recent builds + buildDiscarder(logRotator(numToKeepStr: '10')) + timestamps() + } + + + environment { + REDPITAYA_HOSTNAME = "192.168.178.26" + //REDPITAYA_HOSTNAME = "rp-f03f3a" + //REDPITAYA_HOSTNAME = "nobody.justdied.com" + DOCKER_ARGS = '-u root -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0 --net=host' + //NOSETESTS_COMMAND = 'nosetests pyrpl/test/test_ipython_notebook/test_ipython_kernel.py' + NOSETESTS_COMMAND = 'nosetests' + PYPI = credentials('f63335ce-493d-4caf-8ebe-d7e2629f79f3') + REDPITAYA = credentials('2bf38f88-833a-4624-9682-3a6f0a145d30') + REDPITAYA_USER = "$REDPITAYA_USR" + REDPITAYA_PASSWORD = "$REDPITAYA_PSW" + + } + + agent any + + stages { + stage('Notify github that a build was started') { + agent any + steps { setBuildStatus("Jenkins build started...", "PENDING") }} + stage('Unit tests') { parallel { + stage('Python 3.7') { + agent { dockerfile { args "$DOCKER_ARGS" + additionalBuildArgs '--build-arg PYTHON_VERSION=3.7' }} + steps { lock('redpitaya') { + sh ''' which python + python -V + echo $PYTHON_VERSION + conda list + # use a custom global configfile adapted to the hardware for unit tests + cp ./jenkins_global_config.yml ./pyrpl/config/global_config.yml + python setup.py install + ''' + sh "$NOSETESTS_COMMAND" }} + post { always { junit allowEmptyResults: true, testResults: 'unit_test_results.xml' }}} + stage('Python 3.6') { + agent { dockerfile { args "$DOCKER_ARGS" + additionalBuildArgs '--build-arg PYTHON_VERSION=3.6' }} + steps { lock('redpitaya') { + sh ''' which python + python -V + echo $PYTHON_VERSION + conda list + # use a custom global configfile adapted to the hardware for unit tests + cp ./jenkins_global_config.yml ./pyrpl/config/global_config.yml + python setup.py install + ''' + sh "$NOSETESTS_COMMAND"}} + post { always { junit allowEmptyResults: true, testResults: 'unit_test_results.xml' }}} + /*stage('Python 3.5') { + agent { dockerfile { args "$DOCKER_ARGS" + additionalBuildArgs '--build-arg PYTHON_VERSION=3.5' }} + steps { + sh ''' which python + python -V + echo $PYTHON_VERSION + conda list + # use a custom global configfile adapted to the hardware for unit tests + cp ./jenkins_global_config.yml ./pyrpl/config/global_config.yml + python setup.py install + ''' + sh "$NOSETESTS_COMMAND"} + post { always { junit allowEmptyResults: true, testResults: 'unit_test_results.xml' }}}*/ + stage('Python 2.7') { + agent { dockerfile { args "$DOCKER_ARGS" + additionalBuildArgs '--build-arg PYTHON_VERSION=2.7' }} + steps { lock('redpitaya') { + sh ''' which python + python -V + echo $PYTHON_VERSION + conda list + # use a custom global configfile adapted to the hardware for unit tests + cp ./jenkins_global_config.yml ./pyrpl/config/global_config.yml + python setup.py install + ''' + sh "$NOSETESTS_COMMAND"}} + post { always { junit allowEmptyResults: true, testResults: 'unit_test_results.xml' }}} + stage('Linux binary') { + agent { dockerfile { args '-u root -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0 --net=host' + additionalBuildArgs '--build-arg PYTHON_VERSION=3.7' }} + steps { lock('fake_redpitaya') { + sh ''' apt-get install psmisc + python setup.py install + pip install https://github.com/lneuhaus/pyinstaller/tarball/develop + pyinstaller pyrpl.spec + mv dist/pyrpl ./pyrpl-linux-develop + python .deploy_to_sourceforge.py pyrpl-linux-develop + chmod 755 pyrpl-linux-develop + (./pyrpl-linux-develop config=test_linux hostname=_FAKE_ &) + PYRPL_PID=$! + sleep 30 + killall -9 pyrpl-linux-develop + ''' + //sh 'python .deploy_to_sourceforge.py pyrpl-linux-develop' + }} + post { always { archiveArtifacts allowEmptyArchive: true, artifacts: 'pyrpl-linux-develop', fingerprint: true }}} + stage('pip wheel') { + agent { dockerfile { args '-u root -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0 --net=host' + additionalBuildArgs '--build-arg PYTHON_VERSION=3.7' }} + steps { lock('fake_redpitaya') { + sh ''' python setup.py install + # convert readme file to rst for PyPI + conda install pandoc + pandoc --from=markdown --to=rst --output=README.rst README.md + # make distributions for PyPI + python setup.py sdist + python setup.py bdist_wheel --universal + # upload to PyPI + # twine upload dist/**/*.* + '''}} + post { always { archiveArtifacts allowEmptyArchive: true, artifacts: 'dist/**/*.*', fingerprint: true}}} + }} + stage('Deploy') { + agent { dockerfile { args '-u root -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0 --net=host' + additionalBuildArgs '--build-arg PYTHON_VERSION=3.7' }} + when { + expression { currentBuild.result == null || currentBuild.result == 'SUCCESS'}} + steps { + sh ''' python setup.py install + '''}} + } + post { + failure { + emailext ( + attachLog: true, + subject: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'", + body: """FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]':
+Check console output at ${env.JOB_NAME} [${env.BUILD_NUMBER}]
""", + compressLog: false, + recipientProviders: [requestor(), developers(), brokenTestsSuspects(), brokenBuildSuspects(), upstreamDevelopers(), culprits()], + replyTo: 'pyrpl.readthedocs.io@gmail.com', + to: 'pyrpl.readthedocs.io@gmail.com') + setBuildStatus("Build failed!", "FAILURE") + } + success { setBuildStatus("Build successful!", "SUCCESS") } + unstable { setBuildStatus("Build erroneous!", "ERROR") } + } +} + diff --git a/appveyor.yml b/old_CI_config_files/appveyor.yml similarity index 100% rename from appveyor.yml rename to old_CI_config_files/appveyor.yml diff --git a/azure-pipelines.yml b/old_CI_config_files/azure-pipelines.yml similarity index 100% rename from azure-pipelines.yml rename to old_CI_config_files/azure-pipelines.yml diff --git a/travis_global_config.yml b/old_CI_config_files/travis_global_config.yml similarity index 100% rename from travis_global_config.yml rename to old_CI_config_files/travis_global_config.yml diff --git a/requirements.txt b/requirements.txt index 945c9b46d..6599181e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,17 @@ -. \ No newline at end of file +ipython==8.12.3 +matplotlib==3.9.2 +nbconvert==7.16.4 +nbformat==5.10.4 +netifaces==0.11.0 +numpy==2.1.3 +pandas==2.2.3 +paramiko==3.4.0 +pyqtgraph==0.13.7 +pysine==0.9.2 +PyYAML==6.0.2 +qasync==0.27.1 +QtPy==2.4.2 +ruamel.base==1.0.0 +scipy==1.14.1 +scp==0.15.0 +six==1.16.0 \ No newline at end of file diff --git a/setup.py b/setup.py index a632a088b..fca8e2ef8 100644 --- a/setup.py +++ b/setup.py @@ -43,11 +43,11 @@ def read(fname): #'ruamel.yaml' # temporarily disabled 'pandas', 'pyqtgraph', - 'numpy>=1.9', - 'paramiko>=2.0', - 'nose>=1.0', - 'PyQt5<=5.14', # cannot be installed with pip, if in conda you can use conda install pyqt<5.15 - 'qtpy<=1.10', # qtpy 1.11 contains breaking API changes related to pyqtSignals + 'numpy', + 'paramiko', + 'nose', + 'PyQt5', # cannot be installed with pip, if in conda you can use conda install pyqt<5.15 + 'qtpy', # qtpy 1.11 contains breaking API changes related to pyqtSignals 'nbconvert', 'jupyter-client'] @@ -131,10 +131,11 @@ def compile_server(): #gcc crosscompiler must be installed for this to work author_email='neuhaus@lkb.upmc.fr', url='http://lneuhaus.github.io/pyrpl/', license='MIT', - classifiers=['Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', + classifiers=['Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', 'Programming Language :: C', 'Natural Language :: English', 'Development Status :: 4 - Beta',