From ac491cbf88a04e4829c7f03e11322d5220ebadd6 Mon Sep 17 00:00:00 2001 From: Peter Heesterman Date: Thu, 30 Jul 2026 18:51:38 +0100 Subject: [PATCH 1/4] Re-created from old fork. --- .github/workflows/ci-scripts-build.yml | 4 +++- devsupApp/src/dbfield.c | 17 ++++++++--------- devsupApp/src/devsup/disect.py | 1 + pyIocApp/setup.c | 3 +++ requirements-deb10.txt | 1 - 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index c46ce43..0bbc685 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -1,7 +1,7 @@ name: pyDevSup # Trigger on pushes and PRs to any branch -on: [push, pull_request] +on: [push, pull_request, workflow_dispatch] env: SETUP_PATH: .ci-local:.ci @@ -159,6 +159,8 @@ jobs: python: "3.7" container: "python:3.7" profile: deb10 + test: # no - RuntimeError: Requires Base >=3.15 for iocBuildIsolated() + steps: - uses: actions/checkout@v3 with: diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 94da410..abca9f0 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -3,7 +3,6 @@ #undef _POSIX_C_SOURCE #undef _XOPEN_SOURCE -#include #ifdef HAVE_NUMPY #include #endif @@ -118,21 +117,21 @@ static int assign_array(DBADDR *paddr, PyObject *arr) #ifdef HAVE_NUMPY void *rawfield = paddr->pfield; rset *prset; - PyObject *aval; - PyArrayObject *array = (PyArrayObject *)arr; + PyArrayObject *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(array) != 2 || - PyArray_DIM(array, 0) > (npy_intp) maxlen || + (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(array) != 1 || PyArray_DIM(array, 0) > (npy_intp) maxlen) { + } else if(PyArray_NDIM(array)!=1 || PyArray_DIM(array,0)>maxlen) { PyErr_Format(PyExc_ValueError, "Array has incorrect shape or is too large"); return 1; } @@ -162,14 +161,14 @@ static int assign_array(DBADDR *paddr, PyObject *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((PyArrayObject *)aval)) { + if(elemsize!=PyArray_ITEMSIZE(aval)) { PyErr_Format(PyExc_AssertionError, "item size mismatch %u %u", - elemsize, (unsigned)PyArray_ITEMSIZE((PyArrayObject *)aval)); + elemsize, (unsigned)PyArray_ITEMSIZE(aval) ); Py_DECREF(aval); return 1; } - memcpy(rawfield, PyArray_GETPTR1((PyArrayObject *)aval, 0), insize*elemsize); + memcpy(rawfield, PyArray_GETPTR1(aval, 0), insize*elemsize); Py_DECREF(aval); diff --git a/devsupApp/src/devsup/disect.py b/devsupApp/src/devsup/disect.py index d166f74..b826361 100644 --- a/devsupApp/src/devsup/disect.py +++ b/devsupApp/src/devsup/disect.py @@ -4,6 +4,7 @@ import sys, gc, inspect, time try: + InstanceType = None from types import InstanceType except ImportError: pass # py3 diff --git a/pyIocApp/setup.c b/pyIocApp/setup.c index 61c3861..0f87fe2 100644 --- a/pyIocApp/setup.c +++ b/pyIocApp/setup.c @@ -130,7 +130,10 @@ static void cleanupPrep(initHookState state) static void pySetupReg(void) { Py_InitializeEx(0); +#if NPY_TARGET_VERSION < NPY_1_9_API_VERSION + /* See https://docs.python.org/3/whatsnew/3.9.html */ PyEval_InitThreads(); +#endif setupPyPath(); diff --git a/requirements-deb10.txt b/requirements-deb10.txt index 91aeff2..039a17d 100644 --- a/requirements-deb10.txt +++ b/requirements-deb10.txt @@ -1,3 +1,2 @@ numpy==1.16.2 -#nose==1.3.7 nose2 From 00d9f1cc51724bc400f5d49c99b2bc135a1c6d5b Mon Sep 17 00:00:00 2001 From: Peter Heesterman Date: Tue, 4 Aug 2026 14:22:50 +0100 Subject: [PATCH 2/4] Added typecast in dbfield.c to address compilation on stricter compilers. Added comment in index.rst to note that static builds cannot be used with the module (and why). --- devsupApp/src/dbfield.c | 4 ++-- documentation/index.rst | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index abca9f0..5e9e269 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -131,7 +131,7 @@ static int assign_array(DBADDR *paddr, PyObject *arr) PyErr_Format(PyExc_ValueError, "String array has incorrect shape or is too large"); return 1; - } else if(PyArray_NDIM(array)!=1 || PyArray_DIM(array,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; } @@ -158,7 +158,7 @@ static int assign_array(DBADDR *paddr, PyObject *arr) } Py_XINCREF(desc); - if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE, arr))) + if(!(aval = (PyArrayObject *)PyArray_FromAny(arr, desc, 1, 2, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE, arr))) return 1; if(elemsize!=PyArray_ITEMSIZE(aval)) { diff --git a/documentation/index.rst b/documentation/index.rst index e3a86d1..fd5ad57 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -11,9 +11,18 @@ pydevsup documentation 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 - -File releases are available at https://github.com/mdavidsaver/pyDevSup/releases +It is not possible to use the module with a static build configuration. +The code will build, but it will not work. +The reason is that EPICS database defintions are created in two modules: +1. The _dbapi module creates the defintion of 'Python Device'. +2. The softIocPy module implements device types such as longin that use 'Python Device'. + In a static build, these are held in seperate EPICS databases. + Consequently the softIocPy module does not know what a 'Python Device' is. + In a shared library build there is ony one database, held by the underlying EPICS base library. + +The source can be found at http://github.com/epics-modules/pyDevSup + +File releases are available at https://github.com/epics-modules/pyDevSup/releases Contents: From b5912de43ab98a7917a5bdda23e0c589f20d83c6 Mon Sep 17 00:00:00 2001 From: Peter Heesterman Date: Fri, 14 Aug 2026 15:02:00 +0100 Subject: [PATCH 3/4] Merged c-scripts-build with Windows version. Moved dbfield.c changes to avoid use of assignment-in-condition from long integers & strings PR to here. Setup.c should use Python version (not NumPy version) for logic condition to avoid warning. --- .github/workflows/ci-scripts-build.yml | 33 ++++++++++++++ devsupApp/src/dbfield.c | 59 ++++++++++++++------------ pyIocApp/setup.c | 4 +- 3 files changed, 67 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 0bbc685..6e8aa85 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -161,6 +161,38 @@ jobs: profile: deb10 test: # no - RuntimeError: Requires Base >=3.15 for iocBuildIsolated() + - os: windows-latest + cmp: vs2026 + configuration: default + base: "3.15" + python: "3.11" + profile: latest + test: yes + + - os: windows-latest + cmp: vs2026 + configuration: default + base: "7.0" + python: "3.11" + profile: latest + test: yes + + - os: windows-latest + cmp: vs2026 + configuration: default + base: "7.0" + python: "3.12" + profile: latest + test: yes + + - os: windows-latest + cmp: vs2026 + configuration: default + base: "7.0" + python: "3.13" + profile: latest + test: yes + steps: - uses: actions/checkout@v3 with: @@ -171,6 +203,7 @@ jobs: with: python-version: ${{ matrix.python }} - name: More Setup Python + shell: bash run: | python --version python -m pip --version diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 5e9e269..e215dca 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -116,16 +116,16 @@ static int assign_array(DBADDR *paddr, PyObject *arr) { #ifdef HAVE_NUMPY void *rawfield = paddr->pfield; - rset *prset; - PyArrayObject *aval; + rset *prset = NULL; + PyArrayObject *aval = NULL; 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(array) != 2 || - PyArray_DIM(array, 0) > (npy_intp) maxlen || + (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"); @@ -138,18 +138,20 @@ static int assign_array(DBADDR *paddr, PyObject *arr) insize = PyArray_DIM(array, 0); - if(paddr->special==SPC_DBADDR && - (prset=dbGetRset(paddr)) && - prset->get_array_info) + if(paddr->special==SPC_DBADDR) { - /* array */ - char *datasave=paddr->pfield; - long noe, off; - if(prset->get_array_info(paddr, &noe, &off)) { - PyErr_Format(PyExc_ValueError, "Error fetching array info for %s.%s", - paddr->precord->name, - paddr->pfldDes->name); - return 1; + prset = prset=dbGetRset(paddr); + void *datasave=paddr->pfield; + if (prset->get_array_info) + { + /* array */ + long noe, off; + if(prset->get_array_info(paddr, &noe, &off)) { + PyErr_Format(PyExc_ValueError, "Error fetching array info for %s.%s", + paddr->precord->name, + paddr->pfldDes->name); + return 1; + } } rawfield = paddr->pfield; @@ -163,7 +165,7 @@ static int assign_array(DBADDR *paddr, PyObject *arr) if(elemsize!=PyArray_ITEMSIZE(aval)) { PyErr_Format(PyExc_AssertionError, "item size mismatch %u %u", - elemsize, (unsigned)PyArray_ITEMSIZE(aval) ); + elemsize, (unsigned)PyArray_ITEMSIZE(aval) ); Py_DECREF(aval); return 1; } @@ -172,14 +174,13 @@ static int assign_array(DBADDR *paddr, PyObject *arr) Py_DECREF(aval); - if(paddr->special==SPC_DBADDR && - (prset=dbGetRset(paddr)) && - prset->get_array_info) + if(prset) { - if(prset->put_array_info(paddr, insize)) { - PyErr_Format(PyExc_ValueError, "Error setting array info for %s.%s", - paddr->precord->name, - paddr->pfldDes->name); + if (prset->put_array_info) + if(prset->put_array_info(paddr, insize)) { + PyErr_Format(PyExc_ValueError, "Error setting array info for %s.%s", + paddr->precord->name, + paddr->pfldDes->name); return 1; } } @@ -303,8 +304,8 @@ static PyObject* pyField_putval(pyField *self, PyObject* args) OP(LONG, epicsInt32, PyInt_AsLong); OP(ULONG, epicsUInt32, PyInt_AsLong); #ifdef HAVE_INT64 - OP(INT64, epicsInt32, PyLong_AsLongLong); - OP(UINT64, epicsUInt32, PyLong_AsLongLong); + OP(INT64, epicsInt64, PyLong_AsLongLong); + OP(UINT64, epicsUInt64, PyLong_AsLongLong); #endif OP(FLOAT, epicsFloat32,PyFloat_AsDouble); OP(DOUBLE,epicsFloat64,PyFloat_AsDouble); @@ -321,11 +322,15 @@ static PyObject* pyField_putval(pyField *self, PyObject* args) fld = PyString_AsString(val); #endif if(fld) { - strncpy(dest, fld, MAX_STRING_SIZE); - dest[MAX_STRING_SIZE-1]='\0'; + strncpy(dest, fld, self->addr.field_size); + dest[self->addr.field_size-1]='\0'; } else { dest[0] = '\0'; } + if (self->addr.special == SPC_MOD) + /* This is needed for long string support. */ + if (prset = dbGetRset(&self->addr)) + prset->special(&self->addr, 1); #if PY_MAJOR_VERSION >= 3 Py_DECREF(data); #endif diff --git a/pyIocApp/setup.c b/pyIocApp/setup.c index 0f87fe2..e9e36ca 100644 --- a/pyIocApp/setup.c +++ b/pyIocApp/setup.c @@ -130,8 +130,8 @@ static void cleanupPrep(initHookState state) static void pySetupReg(void) { Py_InitializeEx(0); -#if NPY_TARGET_VERSION < NPY_1_9_API_VERSION - /* See https://docs.python.org/3/whatsnew/3.9.html */ +#if PY_VERSION_HEX < 0x03070000 + /* See https://docs.python.org/3/c-api/threads.html#c.PyEval_InitThreads */ PyEval_InitThreads(); #endif From 2a6fdb08f2cbfb486b0b10c95e4e45d198eebcda Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Mon, 17 Aug 2026 10:32:03 -0700 Subject: [PATCH 4/4] Fix assign_array assignment of prset and add NULL check on prset --- devsupApp/src/dbfield.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index e215dca..90d5be8 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -140,9 +140,9 @@ static int assign_array(DBADDR *paddr, PyObject *arr) if(paddr->special==SPC_DBADDR) { - prset = prset=dbGetRset(paddr); + prset = dbGetRset(paddr); void *datasave=paddr->pfield; - if (prset->get_array_info) + if (prset && prset->get_array_info) { /* array */ long noe, off;