From d9348fa89a7c945d3b4fe2292beda74f449cf8c7 Mon Sep 17 00:00:00 2001 From: tangkong Date: Wed, 15 Jan 2025 09:57:33 -0800 Subject: [PATCH 1/9] TST: try standard pcds build test --- .github/workflows/standard.yml | 25 +++++++++++++++++++++++++ conda-recipe/meta.yaml | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/standard.yml diff --git a/.github/workflows/standard.yml b/.github/workflows/standard.yml new file mode 100644 index 0000000..eac9cf0 --- /dev/null +++ b/.github/workflows/standard.yml @@ -0,0 +1,25 @@ +name: PCDS Standard Testing + +on: + push: + pull_request: + release: + types: + - created + +jobs: + standard: + uses: pcdshub/pcds-ci-helpers/.github/workflows/python-standard.yml@master + secrets: inherit + with: + # The workflow needs to know the package name. This can be determined + # automatically if the repository name is the same as the import name. + package-name: "" + # Extras that will be installed for both conda/pip: + testing-extras: "" + # Extras to be installed only for conda-based testing: + conda-testing-extras: "" + # Extras to be installed only for pip-based testing: + pip-testing-extras: "" + # Set if using setuptools-scm for the conda-build workflow + use-setuptools-scm: true diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index a40f36e..4ad6e2f 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -42,5 +42,5 @@ test: about: home: https://github.com/slaclab/pyca - licence: SLAC Open Licence + licence: SLAC Open License summary: Python Channel Access From 761893bd0c1c94728a1e14d0fa10b76cb43e8f9c Mon Sep 17 00:00:00 2001 From: tangkong Date: Wed, 15 Jan 2025 11:10:52 -0800 Subject: [PATCH 2/9] BLD: only include pip/conda tests, omit docs --- .github/workflows/standard.yml | 61 ++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/.github/workflows/standard.yml b/.github/workflows/standard.yml index eac9cf0..a22e08a 100644 --- a/.github/workflows/standard.yml +++ b/.github/workflows/standard.yml @@ -8,18 +8,57 @@ on: - created jobs: - standard: - uses: pcdshub/pcds-ci-helpers/.github/workflows/python-standard.yml@master + pre-commit: + name: "pre-commit checks" + uses: pcdshub/pcds-ci-helpers/.github/workflows/pre-commit.yml@master + with: + args: "--all-files" + + conda-test: + strategy: + fail-fast: false + matrix: + include: + - python-version: "3.9" + deploy-on-success: true + - python-version: "3.10" + - python-version: "3.11" + experimental: true + - python-version: "3.12" + experimental: true + + name: "Conda" + uses: pcdshub/pcds-ci-helpers/.github/workflows/python-conda-test.yml@master secrets: inherit with: - # The workflow needs to know the package name. This can be determined - # automatically if the repository name is the same as the import name. - package-name: "" - # Extras that will be installed for both conda/pip: + package-name: "pyca" + python-version: ${{ matrix.python-version }} + experimental: ${{ matrix.experimental || false }} + deploy-on-success: ${{ matrix.deploy-on-success || false }} testing-extras: "" - # Extras to be installed only for conda-based testing: - conda-testing-extras: "" - # Extras to be installed only for pip-based testing: - pip-testing-extras: "" - # Set if using setuptools-scm for the conda-build workflow + system-packages: "" use-setuptools-scm: true + + pip-test: + strategy: + fail-fast: false + matrix: + include: + - python-version: "3.9" + deploy-on-success: true + - python-version: "3.10" + - python-version: "3.11" + experimental: true + - python-version: "3.12" + experimental: true + + name: "Pip" + uses: pcdshub/pcds-ci-helpers/.github/workflows/python-pip-test.yml@master + secrets: inherit + with: + package-name: "pyca" + python-version: ${{ matrix.python-version }} + experimental: ${{ matrix.experimental || false }} + deploy-on-success: ${{ matrix.deploy-on-success || false }} + system-packages: "" + testing-extras: "" From afd9ecefcad523a4c4cbf84c9f47f6367db9d66a Mon Sep 17 00:00:00 2001 From: tangkong Date: Wed, 15 Jan 2025 11:36:45 -0800 Subject: [PATCH 3/9] BLD: try adding epicscorelibs to build deps --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b7bf058..7cd93ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] build-backend = "setuptools.build_meta" -requires = [ "setuptools>=45", "setuptools_scm[toml]>=6.2", "numpy"] +requires = [ "setuptools>=45", "setuptools_scm[toml]>=6.2", "numpy", "epicscorelibs"] [project] classifiers = [ "Development Status :: 2 - Pre-Alpha", "Natural Language :: English", "Programming Language :: Python :: 3",] From dcf45517c7852967f02473955f9f7650f12ebad2 Mon Sep 17 00:00:00 2001 From: tangkong Date: Mon, 20 Jan 2025 17:21:53 -0800 Subject: [PATCH 4/9] BLD: adjust build to use epicscorelibs libraries and setuptools_dso --- pyproject.toml | 2 +- requirements.txt | 1 + setup.py | 77 ++++++++++++++++++++++++++++++------------------ 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7cd93ec..83330ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] build-backend = "setuptools.build_meta" -requires = [ "setuptools>=45", "setuptools_scm[toml]>=6.2", "numpy", "epicscorelibs"] +requires = [ "setuptools>=45", "setuptools_scm[toml]>=6.2", "setuptools_dso", "numpy", "epicscorelibs"] [project] classifiers = [ "Development Status :: 2 - Pre-Alpha", "Natural Language :: English", "Programming Language :: Python :: 3",] diff --git a/requirements.txt b/requirements.txt index 24ce15a..049b5f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ +epicscorelibs numpy diff --git a/setup.py b/setup.py index eaad7cf..a3abf43 100644 --- a/setup.py +++ b/setup.py @@ -1,32 +1,53 @@ -import os import sys -import numpy as np -from setuptools import Extension, setup +import numpy +import platform +from setuptools_dso import Extension, setup -if sys.platform == 'darwin': - libsrc = 'Darwin' - compiler = 'clang' -elif sys.platform.startswith('linux'): - libsrc = 'Linux' - compiler = 'gcc' +if (sys.version_info[1] >= 12): + from numpy import get_include + def get_numpy_include_dirs(): + return [get_include()] else: - libsrc = None - -epics_inc = os.getenv("EPICS_BASE") + "/include" -epics_lib = os.getenv("EPICS_BASE") + "/lib/" + os.getenv("EPICS_HOST_ARCH") -numpy_inc = np.get_include() -numpy_lib = np.__path__[0] - -pyca = Extension('pyca', - language='c++', - sources=['pyca/pyca.cc'], - include_dirs=['pyca', epics_inc, - epics_inc + '/os/' + libsrc, - epics_inc + '/compiler/' + compiler, - numpy_inc], - library_dirs=[epics_lib, numpy_lib], - runtime_library_dirs=[epics_lib, numpy_lib], - libraries=['Com', 'ca']) - -setup(ext_modules=[pyca,]) + from numpy.distutils.misc_util import get_numpy_include_dirs + +import epicscorelibs.path +import epicscorelibs.version +from epicscorelibs.config import get_config_var + + +extra = [] +if sys.platform=='linux2': + extra += ['-v'] +elif platform.system()=='Darwin': + # avoid later failure where install_name_tool may run out of space. + # install_name_tool: changing install names or rpaths can't be redone for: + # ... because larger updated load commands do not fit (the program must be relinked, + # and you may need to use -headerpad or -headerpad_max_install_names) + extra += ['-Wl,-headerpad_max_install_names'] + + +pyca = Extension( + name='pyca', + sources=['pyca/pyca.cc'], + include_dirs= get_numpy_include_dirs()+[epicscorelibs.path.include_path], + define_macros = get_config_var('CPPFLAGS'), + extra_compile_args = get_config_var('CXXFLAGS'), + extra_link_args = get_config_var('LDFLAGS')+extra, + dsos = ['epicscorelibs.lib.ca', + 'epicscorelibs.lib.Com' + ], + libraries=get_config_var('LDADD'), +) + +setup( + name='pyca', + description='python channel access library', + packages=['psp', 'pyca'], + ext_modules=[pyca], + install_requires = [ + epicscorelibs.version.abi_requires(), + 'numpy >=%s'%numpy.version.short_version, + ], + zip_safe=False, +) From 9d6874cf3ca718476b8902c8eba66869378ea217 Mon Sep 17 00:00:00 2001 From: tangkong Date: Mon, 20 Jan 2025 17:23:55 -0800 Subject: [PATCH 5/9] BLD: update C++ code for npy2 compatibility (read: make the warnings stop) --- pyca/getfunctions.hh | 4 +++- pyca/putfunctions.hh | 14 +++++++++----- pyca/pyca.cc | 4 +++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pyca/getfunctions.hh b/pyca/getfunctions.hh index c8add59..211fe31 100644 --- a/pyca/getfunctions.hh +++ b/pyca/getfunctions.hh @@ -1,4 +1,5 @@ #include "p3compat.h" +// #include "npy_2_compat.h" // Channel access GET template functions static inline PyObject* _pyca_get(const dbr_string_t value) { @@ -107,7 +108,8 @@ PyObject* _pyca_get_value(capv* pv, const T* dbrv, long count) npy_intp dims[1] = {count}; int typenum = _numpy_array_type(&(dbrv->value)); PyObject* nparray = PyArray_EMPTY(1, dims, typenum, 0); - memcpy(PyArray_DATA(nparray), &(dbrv->value), count*sizeof(dbrv->value)); + PyArrayObject *arr = (PyArrayObject *)PyArray_FROM_O(nparray); + memcpy(PyArray_DATA(arr), &(dbrv->value), count*sizeof(dbrv->value)); return nparray; } else { PyObject* pytup = PyTuple_New(count); diff --git a/pyca/putfunctions.hh b/pyca/putfunctions.hh index 97c3fff..72c30d6 100644 --- a/pyca/putfunctions.hh +++ b/pyca/putfunctions.hh @@ -60,13 +60,16 @@ void _pyca_put_value(capv* pv, PyObject* pyvalue, T** buf, long count) } T* buffer = reinterpret_cast(pv->putbuffer); if (count == 1) { + // if we only want to put the first element if (PyTuple_Check(pyvalue)) { PyObject* pyval = PyTuple_GetItem(pyvalue, 0); _pyca_put(pyval, buffer); } else if (PyArray_Check(pyvalue)) { - void* npdata = PyArray_GETPTR1(pyvalue, 0); + // Convert to array + PyArrayObject *arr = (PyArrayObject *)PyArray_FROM_O(pyvalue); + char* npdata = static_cast(PyArray_GETPTR1(arr, 0)); if (PyArray_IsPythonScalar(pyvalue)) { - PyObject* pyval = PyArray_GETITEM(pyvalue, npdata); + PyObject* pyval = PyArray_GETITEM(arr, npdata); _pyca_put(pyval, buffer); } else { _pyca_put_np(npdata, buffer); @@ -85,11 +88,12 @@ void _pyca_put_value(capv* pv, PyObject* pyvalue, T** buf, long count) _pyca_put(pyval, buffer+i); } } else if (PyArray_Check(pyvalue)) { - bool py_type = PyArray_IsPythonScalar(pyvalue); + PyArrayObject *arr2 = (PyArrayObject *)PyArray_FROM_O(pyvalue); + bool py_type = PyArray_IsPythonScalar(arr2); for (long i=0; i(PyArray_GETPTR1(arr2, i)); if (py_type) { - PyObject* pyval = PyArray_GETITEM(pyvalue, npdata); + PyObject* pyval = PyArray_GETITEM(arr2, npdata); _pyca_put(pyval, buffer+i); } else { _pyca_put_np(npdata, buffer+i); diff --git a/pyca/pyca.cc b/pyca/pyca.cc index b88b038..cab7cc5 100644 --- a/pyca/pyca.cc +++ b/pyca/pyca.cc @@ -1,4 +1,6 @@ #include +// We apparently use deprecated API, but I can't find which bits to update +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include #include #include @@ -785,7 +787,7 @@ extern "C" { Py_INCREF(pyca_caexc); PyModule_AddObject(module, "caexc", pyca_caexc); - PyEval_InitThreads(); + // PyEval_InitThreads(); if (!has_proc_context()) { int result = ca_context_create(ca_enable_preemptive_callback); if (result != ECA_NORMAL) { From 5ddef94bbf35685446d7e76a0b3e6d9c54747cf4 Mon Sep 17 00:00:00 2001 From: tangkong Date: Tue, 21 Jan 2025 08:38:06 -0800 Subject: [PATCH 6/9] BLD: rely only on numpy.get_include, has exsted since numpy 1.18.0. Keep numpy more updated than that (>1.23) --- pyproject.toml | 2 +- requirements.txt | 2 +- setup.py | 9 +++------ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 83330ab..64e90a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] build-backend = "setuptools.build_meta" -requires = [ "setuptools>=45", "setuptools_scm[toml]>=6.2", "setuptools_dso", "numpy", "epicscorelibs"] +requires = [ "setuptools>=45", "setuptools_scm[toml]>=6.2", "setuptools_dso", "numpy>1.23", "epicscorelibs"] [project] classifiers = [ "Development Status :: 2 - Pre-Alpha", "Natural Language :: English", "Programming Language :: Python :: 3",] diff --git a/requirements.txt b/requirements.txt index 049b5f6..2644905 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ epicscorelibs -numpy +numpy>1.23 diff --git a/setup.py b/setup.py index a3abf43..354eb9a 100644 --- a/setup.py +++ b/setup.py @@ -4,12 +4,9 @@ import platform from setuptools_dso import Extension, setup -if (sys.version_info[1] >= 12): - from numpy import get_include - def get_numpy_include_dirs(): - return [get_include()] -else: - from numpy.distutils.misc_util import get_numpy_include_dirs +from numpy import get_include +def get_numpy_include_dirs(): + return [get_include()] import epicscorelibs.path import epicscorelibs.version From 21948d8dabdf8e043ea613e7ad6f3fb08468b86a Mon Sep 17 00:00:00 2001 From: tangkong Date: Tue, 21 Jan 2025 08:40:02 -0800 Subject: [PATCH 7/9] TST: add pytest to dev requirements --- dev-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-requirements.txt b/dev-requirements.txt index 5ee0193..1f73203 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1 +1,2 @@ pcaspy +pytest \ No newline at end of file From 21cc95aaaf77f44a2b2095769271e849a541cb5c Mon Sep 17 00:00:00 2001 From: tangkong Date: Tue, 21 Jan 2025 10:47:53 -0800 Subject: [PATCH 8/9] BLD: try updated conda recipe --- conda-recipe/meta.yaml | 60 ++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 4ad6e2f..07534b0 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,11 +1,10 @@ {% set package_name = "pyca" %} {% set import_name = "pyca" %} -{% set version = load_file_regex(load_file=os.path.join(import_name, "_version.py"), regex_pattern=".*version = '(\S+)'").group(1) %} -{% set EPICS = '3.14.12.6' %} +{% set data = load_setup_py_data() %} package: name: {{ package_name }} - version: {{ version }} + version: {{ data.get('version') }} source: path: .. @@ -14,33 +13,50 @@ build: number: 0 noarch: python script: {{ PYTHON }} -m pip install . -vv - - + skip: true # [win] + missing_dso_whitelist: + - '*/libca.*' + - '*/libCom.*' requirements: build: - - python {{ PY_VER }}* - - epics-base {{ EPICS }}* - - numpy {{ NPY_VER }}* - - setuptools_scm - - pip + - python >=3.9 + - pip + - setuptools + - setuptools_scm + host: + - python >=3.9 + - epicscorelibs + - numpy + - pip + - setuptools + - setuptools_dso + - setuptools_scm run: - - python {{ PY_VER }}* - - epics-base {{ EPICS }}* - - numpy {{ NPY_VER }}* - - + - python + - epicscorelibs + - numpy test: requires: - - pcaspy + - pcaspy imports: - - pyca - - psp - - + - pyca + - psp about: home: https://github.com/slaclab/pyca - licence: SLAC Open License - summary: Python Channel Access + license: LicenseRef-BSD-3-Clause-SLAC + license_family: BSD + license_file: LICENSE.md + summary: PyCA - lightweight bindings for Python applications to access EPICS PVs. + + description: | + PyCA (Python Channel Access) is a module that offers lightweight + bindings for Python applications to access EPICS PVs. It acts as + a channel access client, much like pyepics. The intention of the + module is to provide better performance for embedded applications, + rather than to provide an interactive interface. The most significant + gains will be found when monitoring large waveforms that need to be + processed before exposing them the Python layer. + dev_url: https://github.com/slaclab/pyca From 8c6d75f03448f443c7b3588c660aa5a8d9bf0c5f Mon Sep 17 00:00:00 2001 From: tangkong Date: Tue, 21 Jan 2025 10:50:15 -0800 Subject: [PATCH 9/9] BLD: add epicscorelibs and numpy to build --- conda-recipe/meta.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 07534b0..9ecbe12 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -20,8 +20,10 @@ build: requirements: build: + - epicscorelibs - python >=3.9 - pip + - numpy - setuptools - setuptools_scm host: