From 53ced8e349b1718c86245f37babfbbd07f7dc108 Mon Sep 17 00:00:00 2001 From: AlexWells Date: Wed, 24 Nov 2021 11:59:33 +0000 Subject: [PATCH 1/8] Set minimum supported python to 3.6 --- .github/workflows/code.yml | 7 +------ setup.cfg | 10 +++++----- softioc/fields.py | 18 +++--------------- softioc/imports.py | 34 +++++++++++++--------------------- softioc/softioc.py | 8 +------- tests/conftest.py | 6 ------ 6 files changed, 23 insertions(+), 60 deletions(-) diff --git a/.github/workflows/code.yml b/.github/workflows/code.yml index fe6c928e..3d90a6c2 100644 --- a/.github/workflows/code.yml +++ b/.github/workflows/code.yml @@ -27,12 +27,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python: [cp27, cp36, cp37, cp38, cp39] - - exclude: - # No cothread or asyncio for windows python 2.7 so doesn't work - - os: windows-latest - python: cp27 + python: [cp36, cp37, cp38, cp39] include: # Put coverage in the project directory for mac diff --git a/setup.cfg b/setup.cfg index 94ab6b1a..4f06bd16 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,14 +10,14 @@ long_description_content_type = text/x-rst classifiers = Development Status :: 5 - Production/Stable License :: OSI Approved :: Apache Software License - Programming Language :: Python :: 2.7 + Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 [options] packages = softioc -python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.* +python_requires = >=3.6 [options.entry_points] # Include a command line script @@ -39,7 +39,7 @@ useful = aioca >=1.3 # Dev and docs dependencies dev = - pytest-cov + pytest-cov pytest-flake8 sphinx-rtd-theme-github-versions; python_version > "3.0" pytest-asyncio; python_version > "3.0" @@ -57,8 +57,8 @@ extend-ignore = [tool:pytest] # Run pytest with all our checkers, and don't spam us with massive tracebacks on error # Don't do flake8 here as we need to separate it out for CI -addopts = - --tb=native -vv --doctest-modules --ignore=iocStats --ignore=epicscorelibs --ignore=docs +addopts = + --tb=native -vv --doctest-modules --ignore=iocStats --ignore=epicscorelibs --ignore=docs --cov=softioc --cov-report term --cov-report xml:cov.xml [coverage:run] diff --git a/softioc/fields.py b/softioc/fields.py index 103b74ab..d44dfb69 100644 --- a/softioc/fields.py +++ b/softioc/fields.py @@ -66,18 +66,6 @@ } -if sys.version_info >= (3,): - def decode(string): - return string.decode() - def encode(string): - return string.encode() -else: - def decode(string): - return string - def encode(string): - return string - - class RecordFactory(object): def __init__(self, record_type, fields): '''Uses the EPICS static database to discover the offset in the record @@ -110,9 +98,9 @@ def __getattr__(self, field): if field == 'TIME': return self.__get_time(address) elif field_type == DBF_STRING: - return decode(string_at(cast(address, c_char_p))) + return string_at(cast(address, c_char_p)).decode() elif field_type in [DBF_INLINK, DBF_OUTLINK]: - return decode(cast(address, POINTER(c_char_p))[0]) + return cast(address, POINTER(c_char_p))[0].decode() else: ctypes_type = DbfCodeToCtypes[field_type] return cast(address, POINTER(ctypes_type))[0] @@ -124,7 +112,7 @@ def __setattr__(self, field, value): if field == 'TIME': self.__set_time(address, value) elif field_type == DBF_STRING: - value = encode(str(value)) + value = str(value).encode() buffer = create_string_buffer(value) if size > len(value) + 1: size = len(value) + 1 diff --git a/softioc/imports.py b/softioc/imports.py index 71b59dbd..60d9caba 100644 --- a/softioc/imports.py +++ b/softioc/imports.py @@ -34,27 +34,19 @@ def expect_true(status, function, args): assert status, 'Expected True' -if sys.version_info < (3,): - # Python 2 - auto_encode = c_char_p - def auto_decode(result, func, args): - return result - -else: - # Python 3 - - # Encode all strings to c_char_p - class auto_encode(c_char_p): - encoded = [] - @classmethod - def from_param(cls, value): - if value is None: - return value - else: - return value.encode() - - def auto_decode(result, func, args): - return result.decode() + +# Encode all strings to c_char_p +class auto_encode(c_char_p): + encoded = [] + @classmethod + def from_param(cls, value): + if value is None: + return value + else: + return value.encode() + +def auto_decode(result, func, args): + return result.decode() # int registryDeviceSupportAdd( diff --git a/softioc/softioc.py b/softioc/softioc.py index 216ebf83..c9214142 100644 --- a/softioc/softioc.py +++ b/softioc/softioc.py @@ -310,14 +310,8 @@ def interactive_ioc(context = {}, call_exit = True): exports = dict((key, globals()[key]) for key in command_names) import code - if sys.version_info < (3, 6): - interact_args = {} - else: - # This suppresses irritating exit message introduced by Python3. Alas, - # this option is only available in Python 3.6! - interact_args = dict(exitmsg = '') try: - code.interact(local = dict(exports, **context), **interact_args) + code.interact(local = dict(exports, **context), exitmsg = '') except SystemExit as e: if call_exit: safeEpicsExit(e.code) diff --git a/tests/conftest.py b/tests/conftest.py index 11d5afff..3479fe5c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,12 +7,6 @@ import pytest -if sys.version_info < (3,): - # Python2 has no asyncio, so ignore these tests - collect_ignore = [ - "test_asyncio.py", "sim_asyncio_ioc.py", "sim_asyncio_ioc_override.py" - ] - class SubprocessIOC: def __init__(self, ioc_py): self.pv_prefix = "".join( From 5870e1887ecac561558016d4b785ba0d5f27b422 Mon Sep 17 00:00:00 2001 From: AlexWells Date: Wed, 24 Nov 2021 12:06:15 +0000 Subject: [PATCH 2/8] Add autoformatting to VSCode on save action. As we don't have Black formatter running, this at least provides some of the functionality without breaking any existing formatting. --- .vscode/settings.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 61c6dc1c..f21c98de 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,4 +7,6 @@ "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "python.languageServer": "Pylance", + "files.trimTrailingWhitespace": true, + "files.trimFinalNewlines": true, } From 715f9c3b01e7e87408f35641633084a2bbcd49b0 Mon Sep 17 00:00:00 2001 From: AlexWells Date: Wed, 24 Nov 2021 12:56:36 +0000 Subject: [PATCH 3/8] Remove another Python version check Turns out I hadn't saved the file before previous commit... --- softioc/device_core.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/softioc/device_core.py b/softioc/device_core.py index ab2ce92f..c11f0d4f 100644 --- a/softioc/device_core.py +++ b/softioc/device_core.py @@ -126,8 +126,7 @@ class DSET(DSET_BASE): # Hang onto the values we publish to EPICS to ensure that they persist! # We also need to ensure that the device name persits. cls.__dset = dset - if sys.version_info >= (3,): - cls._device_name_ = cls._device_name_.encode() + cls._device_name_ = cls._device_name_.encode() imports.registryDeviceSupportAdd(cls._device_name_, byref(cls.__dset)) From 878ebac092068a2014ce74aa38b5aa949dc7c9c6 Mon Sep 17 00:00:00 2001 From: AlexWells Date: Thu, 25 Nov 2021 11:17:34 +0000 Subject: [PATCH 4/8] Remove unnecessary Python version specifications --- setup.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 4f06bd16..26faed7f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,9 +41,9 @@ useful = dev = pytest-cov pytest-flake8 - sphinx-rtd-theme-github-versions; python_version > "3.0" - pytest-asyncio; python_version > "3.0" - aioca >=1.3 ; python_version > "3.0" + sphinx-rtd-theme-github-versions + pytest-asyncio + aioca >=1.3 cothread; sys_platform != "win32" p4p From f0d27e83a33c8b37f481ed7208166aee143bb2fe Mon Sep 17 00:00:00 2001 From: AlexWells Date: Tue, 30 Nov 2021 12:50:12 +0000 Subject: [PATCH 5/8] Remove Python version checks from C code --- softioc/extension.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/softioc/extension.c b/softioc/extension.c index c04ff630..2570d7f1 100644 --- a/softioc/extension.c +++ b/softioc/extension.c @@ -13,11 +13,6 @@ #include #include -/* In Python3 this function has been renamed. */ -#if PY_MAJOR_VERSION >= 3 -#define PyInt_FromLong(value) PyLong_FromLong(value) -#endif - /* Reference stealing version of PyDict_SetItemString */ static void set_dict_item_steal( PyObject *dict, const char *name, PyObject *py_value) @@ -28,7 +23,7 @@ static void set_dict_item_steal( /* Helper for function below. */ #define ADD_ENUM(dict, name) \ - set_dict_item_steal(dict, #name, PyInt_FromLong(name)) + set_dict_item_steal(dict, #name, PyLong_FromLong(name)) /* Alas, EPICS has changed the numerical assignments of the DBF_ enums between * versions, so to avoid unpleasant surprises, we compute thes values here in C @@ -226,7 +221,7 @@ static struct PyMethodDef softioc_methods[] = { {NULL, NULL, 0, NULL} /* Sentinel */ }; -#if PY_MAJOR_VERSION >= 3 + static struct PyModuleDef softioc_module = { PyModuleDef_HEAD_INIT, "softioc._extension", @@ -234,19 +229,12 @@ static struct PyModuleDef softioc_module = { -1, softioc_methods, }; -#endif -#if PY_MAJOR_VERSION >= 3 -# define PyMOD(NAME) PyObject* PyInit_##NAME (void) -#else -# define PyMOD(NAME) void init##NAME (void) -#endif + +#define PyMOD(NAME) PyObject* PyInit_##NAME (void) + PyMOD(_extension) { -#if PY_MAJOR_VERSION >= 3 return PyModule_Create(&softioc_module); -#else - Py_InitModule("softioc._extension", softioc_methods); -#endif } From 9d03b9bfa3d30f8970ed5295f73e8fa7dfe1558f Mon Sep 17 00:00:00 2001 From: AlexWells Date: Tue, 30 Nov 2021 12:50:42 +0000 Subject: [PATCH 6/8] Remove unused function --- softioc/imports.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/softioc/imports.py b/softioc/imports.py index 60d9caba..e6349a00 100644 --- a/softioc/imports.py +++ b/softioc/imports.py @@ -45,9 +45,6 @@ def from_param(cls, value): else: return value.encode() -def auto_decode(result, func, args): - return result.decode() - # int registryDeviceSupportAdd( # const char *name,const struct dset *pdset); From 95a0f562e6a3a2f8462204720a594c010fe4ad05 Mon Sep 17 00:00:00 2001 From: AlexWells Date: Tue, 30 Nov 2021 12:52:14 +0000 Subject: [PATCH 7/8] Add changelog note --- CHANGELOG.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1675bebd..dbf9a58c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,7 +9,9 @@ and this project adheres to `Semantic Versioning ` 3.2.1_ - 2021-11-25 ------------------- @@ -20,7 +22,7 @@ Changed: Added: -- Provide logging for exceptions raised in callbacks +- Provide logging for exceptions raised in callbacks Fixed: From daf58b2d734ea8e506a2bef3b9c7a9cb9b9b6efc Mon Sep 17 00:00:00 2001 From: AlexWells Date: Tue, 30 Nov 2021 14:43:23 +0000 Subject: [PATCH 8/8] Remove more unused items --- softioc/device_core.py | 2 +- softioc/extension.c | 6 +----- softioc/imports.py | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/softioc/device_core.py b/softioc/device_core.py index c11f0d4f..da81c5d1 100644 --- a/softioc/device_core.py +++ b/softioc/device_core.py @@ -124,7 +124,7 @@ class DSET(DSET_BASE): setattr(dset, method_name, callback) # Hang onto the values we publish to EPICS to ensure that they persist! - # We also need to ensure that the device name persits. + # We also need to ensure that the device name persists. cls.__dset = dset cls._device_name_ = cls._device_name_.encode() imports.registryDeviceSupportAdd(cls._device_name_, byref(cls.__dset)) diff --git a/softioc/extension.c b/softioc/extension.c index 2570d7f1..3ab7b2c4 100644 --- a/softioc/extension.c +++ b/softioc/extension.c @@ -230,11 +230,7 @@ static struct PyModuleDef softioc_module = { softioc_methods, }; - -#define PyMOD(NAME) PyObject* PyInit_##NAME (void) - - -PyMOD(_extension) +PyObject *PyInit__extension(void) { return PyModule_Create(&softioc_module); } diff --git a/softioc/imports.py b/softioc/imports.py index e6349a00..eb525fb8 100644 --- a/softioc/imports.py +++ b/softioc/imports.py @@ -37,7 +37,6 @@ def expect_true(status, function, args): # Encode all strings to c_char_p class auto_encode(c_char_p): - encoded = [] @classmethod def from_param(cls, value): if value is None: