diff --git a/.ci b/.ci index 899b183..4e4f33e 160000 --- a/.ci +++ b/.ci @@ -1 +1 @@ -Subproject commit 899b18336b4ce3bd9328fd30c33621224c78a4d7 +Subproject commit 4e4f33e54f59343c77342200a95800073661e7ac diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 6729366..c46ce43 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -11,8 +11,9 @@ env: jobs: build-base: - name: ${{ matrix.base }}/${{ matrix.os }}/${{ matrix.python }}/${{ matrix.extra }} + name: ${{ matrix.base }}/${{ matrix.os }}/${{ matrix.profile }}/${{ matrix.python }}/${{ matrix.extra }} runs-on: ${{ matrix.os }} + container: ${{ matrix.container }} # Set environment variables from matrix parameters env: CMP: ${{ matrix.cmp }} @@ -33,6 +34,49 @@ jobs: base: "7.0" python: "3.7" profile: deb10 + container: "python:3.7" + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.9" + profile: deb11 + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.11" + profile: deb12 + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.13" + profile: deb13 + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.6" + container: "python:3.6" + profile: latest + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.7" + container: "python:3.7" + profile: latest test: yes - os: ubuntu-latest @@ -59,6 +103,30 @@ jobs: profile: latest test: yes + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.11" + profile: latest + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.12" + profile: latest + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.13" + profile: latest + test: yes + - os: macos-latest cmp: gcc configuration: default @@ -72,20 +140,31 @@ jobs: configuration: default base: "3.15" python: "3.7" + container: "python:3.7" profile: deb10 test: yes + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "3.15" + python: "3.13" + profile: deb13 + test: yes + - os: ubuntu-latest cmp: gcc configuration: default base: "3.14" python: "3.7" + container: "python:3.7" profile: deb10 steps: - uses: actions/checkout@v3 with: submodules: true - name: Set up Python ${{ matrix.python }} + if: ${{ !matrix.container }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} diff --git a/devsupApp/src/dbapi.c b/devsupApp/src/dbapi.c index f859cd6..ccbc69c 100644 --- a/devsupApp/src/dbapi.c +++ b/devsupApp/src/dbapi.c @@ -289,11 +289,11 @@ static struct PyMethodDef dbapimethod[] = { #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef dbapimodule = { - PyModuleDef_HEAD_INIT, + PyModuleDef_HEAD_INIT, "devsup._dbapi", NULL, -1, - &dbapimethod + dbapimethod }; #endif diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 4a03cba..94da410 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -40,6 +40,10 @@ static const int dbf2np_map[DBF_MENU+1] = { NPY_INT16, // DBF_MENU }; static PyArray_Descr* dbf2np[DBF_MENU+1]; +#if NPY_ABI_VERSION < 0x02000000 + #define PyDataType_ELSIZE(descr) ((descr)->elsize) + #define PyDataType_SET_ELSIZE(descr, size) (descr)->elsize = size +#endif #endif typedef struct { @@ -98,10 +102,10 @@ static PyObject* build_array(PyObject* obj, void *data, unsigned short ftype, un desc = dbf2np[ftype]; if(ftype==DBF_STRING) { - desc->elsize = MAX_STRING_SIZE; + PyDataType_SET_ELSIZE(desc, MAX_STRING_SIZE); } - Py_XINCREF(desc); + Py_XINCREF(desc); // take a reference for PyArray_NewFromDescr() to steal return PyArray_NewFromDescr(&PyArray_Type, desc, ndims, dims, NULL, data, flags, (PyObject*)obj); #else PyErr_SetNone(PyExc_NotImplementedError); @@ -115,22 +119,25 @@ static int assign_array(DBADDR *paddr, PyObject *arr) void *rawfield = paddr->pfield; rset *prset; PyObject *aval; + PyArrayObject *array = (PyArrayObject *)arr; unsigned elemsize = dbValueSize(paddr->field_type); unsigned long maxlen = paddr->no_elements, insize; PyArray_Descr *desc = dbf2np[paddr->field_type]; if(paddr->field_type==DBF_STRING && - (PyArray_NDIM(arr)!=2 || PyArray_DIM(arr,0)>maxlen || PyArray_DIM(arr,1)!=MAX_STRING_SIZE)) + (PyArray_NDIM(array) != 2 || + PyArray_DIM(array, 0) > (npy_intp) maxlen || + PyArray_DIM(array, 1) != MAX_STRING_SIZE)) { PyErr_Format(PyExc_ValueError, "String array has incorrect shape or is too large"); return 1; - } else if(PyArray_NDIM(arr)!=1 || PyArray_DIM(arr,0)>maxlen) { + } else if(PyArray_NDIM(array) != 1 || PyArray_DIM(array, 0) > (npy_intp) maxlen) { PyErr_Format(PyExc_ValueError, "Array has incorrect shape or is too large"); return 1; } - insize = PyArray_DIM(arr, 0); + insize = PyArray_DIM(array, 0); if(paddr->special==SPC_DBADDR && (prset=dbGetRset(paddr)) && @@ -152,16 +159,17 @@ static int assign_array(DBADDR *paddr, PyObject *arr) } Py_XINCREF(desc); - if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_CARRAY, arr))) + if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE, arr))) return 1; - if(elemsize!=PyArray_ITEMSIZE(aval)) { + if(elemsize!=PyArray_ITEMSIZE((PyArrayObject *)aval)) { PyErr_Format(PyExc_AssertionError, "item size mismatch %u %u", - elemsize, (unsigned)PyArray_ITEMSIZE(aval) ); + elemsize, (unsigned)PyArray_ITEMSIZE((PyArrayObject *)aval)); + Py_DECREF(aval); return 1; } - memcpy(rawfield, PyArray_GETPTR1(aval, 0), insize*elemsize); + memcpy(rawfield, PyArray_GETPTR1((PyArrayObject *)aval, 0), insize*elemsize); Py_DECREF(aval); @@ -207,7 +215,7 @@ static PyObject* pyField_getval(pyField *self) if(self->addr.no_elements>1) { return build_array((PyObject*)self, rawfield, self->addr.field_type, - noe, NPY_CARRAY_RO); + noe, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED); } } @@ -362,7 +370,7 @@ static PyObject *pyField_getarray(pyField *self) } else data = self->addr.pfield; - return build_array((PyObject*)self, data, self->addr.field_type, self->addr.no_elements, NPY_CARRAY); + return build_array((PyObject*)self, data, self->addr.field_type, self->addr.no_elements, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE); } static PyObject *pyField_getlen(pyField *self) diff --git a/documentation/environment.rst b/documentation/environment.rst index a33677b..076d7cb 100644 --- a/documentation/environment.rst +++ b/documentation/environment.rst @@ -4,7 +4,7 @@ Runtime Environment The pyDevSup module initializes the interpreter during the registration phase of IOC startup with the *pySetupReg* registrar function. :: - #!../../bin/linux-x86_64/softIocPy2.7 + #!../../bin/linux-x86_64/softIocPy3.6 # Interpreter not started dbLoadDatabase("../../dbd/softIocPy.dbd",0,0) softIocPy_registerRecordDeviceDriver(pdbbase) @@ -51,7 +51,7 @@ file. :: The default or preferred Python version can be specificed in *configure/CONFIG_SITE* :: - PY_VER ?= 2.7 + PY_VER ?= 3.6 The following should be added to individual EPICS Makefiles. :: @@ -64,8 +64,8 @@ The following should be added to individual EPICS Makefiles. :: This will add or amend several make variables. The ``USR_*FLAGS`` variables may be extended with appropriate flags for building python modules. The ``PY_VER`` -variable is defined with the Python version number found in install directories (eg "2.7"). -The ``PY_LD_VER`` variable is defined with the python library version number (eg "3.2mu"), +variable is defined with the Python version number found in install directories (eg "3.6"). +The ``PY_LD_VER`` variable is defined with the python library version number (eg "3.6mu"), which may be the same as ``PY_VER``. Include pyDevSup in your IOC @@ -113,11 +113,11 @@ Installing for several Python versions The recipe for building and installing the pyDevSup module for several python version side by side is :: - make PY_VER=2.6 + make PY_VER=3.6 make clean - make PY_VER=2.7 + make PY_VER=3.10 make clean - make PY_VER=3.2 + make PY_VER=3.14 make clean The ``PYTHON`` make variable can be specified if the interpreter executable diff --git a/documentation/gettingstarted.rst b/documentation/gettingstarted.rst index ef542ef..294494a 100644 --- a/documentation/gettingstarted.rst +++ b/documentation/gettingstarted.rst @@ -24,7 +24,7 @@ The :py:meth:`process ` method increments the *VAL* field Start this IOC with. :: - $ ./bin/linux-x86_64/softIocPy2.7 -d cntrec.db + $ ./bin/linux-x86_64/softIocPy3.6 -d cntrec.db Starting iocInit ... iocRun: All initialization complete diff --git a/documentation/index.rst b/documentation/index.rst index 2acf7b1..e3a86d1 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -8,7 +8,7 @@ pydevsup documentation *pyDevSup* is a means of writing EPICS device support code in Python. -It currently supports EPICS >=3.14.12 and python versions: 2.7, and >=3.2. +It currently supports EPICS >=3.14.12 and python versions >=3.6 The numpy package is also required. The source can be found at http://github.com/mdavidsaver/pyDevSup diff --git a/iocBoot/iocapplmon/st.cmd b/iocBoot/iocapplmon/st.cmd index c931fb9..142d051 100755 --- a/iocBoot/iocapplmon/st.cmd +++ b/iocBoot/iocapplmon/st.cmd @@ -1,4 +1,4 @@ -#!../../bin/linux-x86/softIocPy2.7 +#!../../bin/linux-x86/softIocPy3.6 < envPaths diff --git a/iocBoot/iocarchivemon/st.cmd b/iocBoot/iocarchivemon/st.cmd index 20fef52..be83af7 100755 --- a/iocBoot/iocarchivemon/st.cmd +++ b/iocBoot/iocarchivemon/st.cmd @@ -1,4 +1,4 @@ -#!../../bin/linux-x86/softIocPy2.7 +#!../../bin/linux-x86/softIocPy3.6 < envPaths diff --git a/iocBoot/iocarchivemon/st.cmd.main b/iocBoot/iocarchivemon/st.cmd.main index df00b9c..ea10a94 100755 --- a/iocBoot/iocarchivemon/st.cmd.main +++ b/iocBoot/iocarchivemon/st.cmd.main @@ -1,4 +1,4 @@ -#!../../bin/linux-x86_64/softIocPy2.7 +#!../../bin/linux-x86_64/softIocPy3.6 < envPaths diff --git a/makehelper.py b/makehelper.py index ef36d63..05fd147 100644 --- a/makehelper.py +++ b/makehelper.py @@ -26,15 +26,30 @@ pass out = open(sys.argv[1], 'w') -from distutils.sysconfig import get_config_var, get_python_inc +""" +3.2 sysconfig +3.10 sysconfig.get_path +3.10.13 distutils is deprecated. +3.12 distutils was removed. +""" +if sys.version_info >= (3,10,): + from sysconfig import get_config_var, get_path + incdirs = [get_path("include")] +else: + from distutils.sysconfig import get_config_var, get_python_inc + incdirs = [get_python_inc()] -incdirs = [get_python_inc()] libdir = get_config_var('LIBDIR') or '' have_np='NO' + +""" +numpy 1.18, numpy.get_include() +""" try: - from numpy.distutils.misc_util import get_numpy_include_dirs - incdirs = get_numpy_include_dirs()+incdirs + from numpy import get_include + numpy_dir = [get_include()] + incdirs = numpy_dir+incdirs have_np='YES' except ImportError: pass diff --git a/requirements-deb11.txt b/requirements-deb11.txt new file mode 100644 index 0000000..bc9b6d9 --- /dev/null +++ b/requirements-deb11.txt @@ -0,0 +1,2 @@ +numpy==1.19.5 +nose2==0.9.2 diff --git a/requirements-deb12.txt b/requirements-deb12.txt new file mode 100644 index 0000000..13118a8 --- /dev/null +++ b/requirements-deb12.txt @@ -0,0 +1,2 @@ +numpy==1.24.2 +nose2==0.12.0 diff --git a/requirements-deb13.txt b/requirements-deb13.txt new file mode 100644 index 0000000..abb51c7 --- /dev/null +++ b/requirements-deb13.txt @@ -0,0 +1,2 @@ +numpy==2.2.4 +nose2==0.15.1