From fcd5b60d36edae980488ccadb24e793bc0ced19c Mon Sep 17 00:00:00 2001 From: Peter Heesterman Date: Mon, 7 Sep 2026 17:14:09 +0100 Subject: [PATCH 1/3] Added /bat files to operate those examples that can work on Windows. Changed Python files to work with Python3. Added bplstorage.db to the relevant makefile. --- archApp/Makefile | 1 + archApp/bplreport.py | 27 +++++++++++++++------------ devsupApp/src/devsup/disect.py | 8 -------- iocBoot/env_vars.bat | 25 +++++++++++++++++++++++++ iocBoot/iocapplmon/st.bat | 6 ++++++ iocBoot/iocarchivemon/st.bat | 6 ++++++ iocBoot/iocweatherbnl/st.bat | 8 ++++++++ iocBoot/iocweatherbnl/st.cmd | 6 +++--- 8 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 iocBoot/env_vars.bat create mode 100644 iocBoot/iocapplmon/st.bat create mode 100644 iocBoot/iocarchivemon/st.bat create mode 100644 iocBoot/iocweatherbnl/st.bat diff --git a/archApp/Makefile b/archApp/Makefile index 36838b9..27968d8 100644 --- a/archApp/Makefile +++ b/archApp/Makefile @@ -6,6 +6,7 @@ include $(TOP)/configure/CONFIG_PY PY += bplreport.py DB += applmetrics.db +DB += bplstorage.db include $(TOP)/configure/RULES include $(TOP)/configure/RULES_PY diff --git a/archApp/bplreport.py b/archApp/bplreport.py index ac0d86e..aece607 100644 --- a/archApp/bplreport.py +++ b/archApp/bplreport.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -import time, sched, urllib2, json +import time, sched, urllib, json +import urllib.request # https://stackoverflow.com/questions/37042152/python-3-5-1-urllib-has-no-attribute-request from devsup.db import IOScanListBlock from devsup.hooks import initHook from devsup.util import StoppableThread @@ -20,19 +21,21 @@ def fail(self): def process(self): self.result = None - R = urllib2.urlopen(self.url, timeout=3) + R = None try: + R = urllib.request.urlopen(self.url, timeout=3) if R.getcode()!=200: - print 'Fail',R.getcode(), self.url + print ('Fail',R.getcode(), self.url) self.result = None return self.result = json.load(R) except: - print 'Error fetching',self.url + print ('Error fetching',self.url) import traceback traceback.print_exc() finally: - R.close() + if R is not None: + R.close() self.result_time = time.time() self.scan.interrupt(reason = self.result) @@ -51,7 +54,7 @@ def _proc(self, R): try: R.process() except: - print 'Error in processing',R.url + print ('Error in processing',R.url) import traceback traceback.print_exc() R.fail() @@ -59,15 +62,15 @@ def _proc(self, R): def run(self): self._S = S = sched.scheduler(time.time, self._sleep) - for R in BPLReport.reports.itervalues(): + for R in iter(BPLReport.reports.values()): S.enter(0, 0, self._proc, (R,)) try: S.run() except self._Done: - print 'BPL worker exit' + print ('BPL worker exit') except: - print 'Error in scheduler' + print ('Error in scheduler') import traceback traceback.print_exc() @@ -76,13 +79,13 @@ def run(self): @initHook("AfterIocRunning") def _startWorker(): _worker.start() - print 'BPL worker started' + print ('BPL worker started') @initHook("AtIocExit") def _stopWorker(): - print 'BPL worker stopping' + print ('BPL worker stopping') _worker.join() - print 'BPL worker stopped' + print ('BPL worker stopped') class ReportItem(object): raw = True diff --git a/devsupApp/src/devsup/disect.py b/devsupApp/src/devsup/disect.py index b826361..5e48f33 100644 --- a/devsupApp/src/devsup/disect.py +++ b/devsupApp/src/devsup/disect.py @@ -3,11 +3,6 @@ from __future__ import print_function import sys, gc, inspect, time -try: - InstanceType = None - from types import InstanceType -except ImportError: - pass # py3 class StatsDelta(object): """GC statistics tracking. @@ -82,9 +77,6 @@ def gcstats(): if K is StatsDelta: continue # avoid counting ourselves - elif InstanceType is not None and K is InstanceType: # instance of an old-style class - K = getattr(obj, '__class__', K) - # Track types as strings to avoid holding references K = str(K) diff --git a/iocBoot/env_vars.bat b/iocBoot/env_vars.bat new file mode 100644 index 0000000..c63f53b --- /dev/null +++ b/iocBoot/env_vars.bat @@ -0,0 +1,25 @@ +@echo off +REM This script extracts the: +REM PATH to the Python install. On Windows, this is not a system path. +REM The value of the used Python version makefile variable. It is applied to the executable to be loaded. +set TOP=%~dp0.. +set CONFIG_PY=%TOP%\configure\os\CONFIG_PY.Common.windows-x64 +REM https://stackoverflow.com/questions/232747/read-environment-variables-from-file-in-windows-batch-cmd-exe +setlocal EnableDelayedExpansion +for /F "tokens=1,2 delims==" %%i in ('type %CONFIG_PY%') do ( + set rawtoken=%%i + REM rawtoken still ends with the " :" of the " := " text. + set token=!rawtoken:~0,-2%! + set rawvalue=%%j + REM rawvalue still begins with the " " of the " := " text. + set value=!rawvalue:~1%! + if "!token!"=="PY_VER" ( + set PY_VER="!value!" + ) + if "!token!"=="PY_LIBDIRS" ( + REM remove the "\libs" from the end of the string + set PYTHON=!value:~0,-5%! + ) +) +REM https://stackoverflow.com/questions/15494688/batch-script-make-setlocal-variable-accessed-by-other-batch-files +endlocal & set PATH=%PYTHON%;C:\Windows & set PY_VER=%PY_VER% diff --git a/iocBoot/iocapplmon/st.bat b/iocBoot/iocapplmon/st.bat new file mode 100644 index 0000000..177760b --- /dev/null +++ b/iocBoot/iocapplmon/st.bat @@ -0,0 +1,6 @@ +@echo off +set OLD_PATH=%PATH% +call ..\env_vars.bat +call dllPath.bat +%TOP%\bin\windows-x64\softIocPy%PY_VER%.exe st.cmd +set PATH=%OLD_PATH% diff --git a/iocBoot/iocarchivemon/st.bat b/iocBoot/iocarchivemon/st.bat new file mode 100644 index 0000000..177760b --- /dev/null +++ b/iocBoot/iocarchivemon/st.bat @@ -0,0 +1,6 @@ +@echo off +set OLD_PATH=%PATH% +call ..\env_vars.bat +call dllPath.bat +%TOP%\bin\windows-x64\softIocPy%PY_VER%.exe st.cmd +set PATH=%OLD_PATH% diff --git a/iocBoot/iocweatherbnl/st.bat b/iocBoot/iocweatherbnl/st.bat new file mode 100644 index 0000000..e6d0642 --- /dev/null +++ b/iocBoot/iocweatherbnl/st.bat @@ -0,0 +1,8 @@ +@echo off +REM requires the pymetar module installed. +set OLD_PATH=%PATH% +call ..\env_vars.bat +call dllPath.bat +%TOP%\bin\windows-x64\softIocPy%PY_VER%.exe st.cmd +set PATH=%OLD_PATH% + diff --git a/iocBoot/iocweatherbnl/st.cmd b/iocBoot/iocweatherbnl/st.cmd index a95b288..ad2bbf6 100755 --- a/iocBoot/iocweatherbnl/st.cmd +++ b/iocBoot/iocweatherbnl/st.cmd @@ -8,9 +8,9 @@ cd("$(TOP)") #epicsEnvSet("PYTHONPATH", "${TOP}/python/$(ARCH)") -dbLoadRecords("db/weather.db","P=CF:Ext{KISP},LOC=KISP") -#dbLoadRecords("db/weather.db","P=CF:Ext{KHWV},LOC=KHWV") -dbLoadRecords("db/weather.db","P=CF:Ext{EGTK},LOC=EGTK") +dbLoadRecords("db/weather.db","P=CF:Ext{KISP},LOC=KISP") # Long Island MacArthur Airport +#dbLoadRecords("db/weather.db","P=CF:Ext{KHWV},LOC=KHWV") # Brookhaven Calabro Airport +dbLoadRecords("db/weather.db","P=CF:Ext{EGTK},LOC=EGTK") # London Oxford Airport (Kidlington) iocInit() From ba45c0a0c8f9df6aa81b3262ff60655d0201ade7 Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Tue, 6 Oct 2026 10:23:49 -0700 Subject: [PATCH 2/3] Update archiver mon demo app for py3 and fix INP links for floats --- archApp/bplreport.py | 4 ++-- archApp/bplstorage.db | 4 ++-- iocBoot/iocapplmon/st.cmd | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/archApp/bplreport.py b/archApp/bplreport.py index aece607..14aca57 100644 --- a/archApp/bplreport.py +++ b/archApp/bplreport.py @@ -107,7 +107,7 @@ def process_fetch_float(self, rec, reason=None): invalid = True if R is not None and len(R)>self.idx: try: - rec.VAL = float(str(R[self.idx][self.attrib]).translate(None,',')) + rec.VAL = float(str(R[self.idx][self.attrib]).replace(',', '')) except KeyError: pass else: @@ -135,7 +135,7 @@ def process_fetch_string(self, rec, reason=None): invalid = True if R is not None and len(R)>self.idx: try: - rec.VAL = R[self.idx][self.attrib].encode('ascii') + rec.VAL = R[self.idx][self.attrib] except KeyError: pass else: diff --git a/archApp/bplstorage.db b/archApp/bplstorage.db index 323127c..d05d175 100644 --- a/archApp/bplstorage.db +++ b/archApp/bplstorage.db @@ -7,14 +7,14 @@ record(stringin, "$(P)Name:$(N)-I") { record(ai, "$(P)Size:$(N)-I") { field(DTYP, "Python Device") - field(INP , "@bplreport fetch_string storage.$(N).available_space") + field(INP , "@bplreport fetch_float storage.$(N).available_space") field(SCAN, "I/O Intr") field(TSE , "-2") } record(ai, "$(P)Pcnt:$(N)-I") { field(DTYP, "Python Device") - field(INP , "@bplreport fetch_string storage.$(N).available_space_percent") + field(INP , "@bplreport fetch_float storage.$(N).available_space_percent") field(SCAN, "I/O Intr") field(TSE , "-2") field(HOPR, "100") diff --git a/iocBoot/iocapplmon/st.cmd b/iocBoot/iocapplmon/st.cmd index f345464..013afbb 100755 --- a/iocBoot/iocapplmon/st.cmd +++ b/iocBoot/iocapplmon/st.cmd @@ -2,7 +2,7 @@ < envPaths -#epicsEnvSet("APPLNAME", "arcapp01.cs.nsls2.local:17665") +# Update to your archiver mgmt endpoint epicsEnvSet("APPLNAME", "capp02.cs.nsls2.local:17665") py "import bplreport" From 5a941d03b83c233681d1d36f6b8631d14026048d Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Tue, 6 Oct 2026 10:46:23 -0700 Subject: [PATCH 3/3] update a few py2 items to py3 in demo FPM and caputlog IOCs --- iocBoot/iocFPM/fpm.py | 8 ++++---- iocBoot/iocFPM/loadnp.py | 2 +- iocBoot/iocFPM/st.cmd | 2 +- iocBoot/ioccaputlog/st.cmd | 2 +- logApp/src/inotifyy.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iocBoot/iocFPM/fpm.py b/iocBoot/iocFPM/fpm.py index 708a336..ae25631 100644 --- a/iocBoot/iocFPM/fpm.py +++ b/iocBoot/iocFPM/fpm.py @@ -40,7 +40,7 @@ remd = mult-nPb assert remd<0.5 and remd>0, "assumption violated" # remd==0 drops no samples, remd>0.5 should add samples delta = int(numpy.round(nPb/remd)) -print 'fpm delta mult', nPb, 'frac', delta +print('fpm delta mult', nPb, 'frac', delta) def deleteEveryNth(arr, N): '''Optimized version of @@ -83,7 +83,7 @@ def inThread(self, raw=None, nskip=0, thres=0.01, scale=1.0, offset=0, **kws): raw = deleteEveryNth(raw, delta) # truncate to whole turns - turns = len(raw)/sampPturn + turns = len(raw)//sampPturn raw = raw[:turns*sampPturn] # determine buckets w/ beam @@ -129,7 +129,7 @@ def inThread(self, raw=None, nskip=0, thres=0.01, scale=1.0, offset=0, **kws): fill *= S1 S2 = scale/fillbyturn[0] fillbyturn *= S2 - #print 'factor', S1, S2 + #print('factor', S1, S2) else: fill = numpy.zeros(fill.shape, dtype=fill.dtype) fillbyturn = numpy.zeros(fillbyturn.shape, dtype=fillbyturn.dtype) @@ -145,7 +145,7 @@ def inThread(self, raw=None, nskip=0, thres=0.01, scale=1.0, offset=0, **kws): bindx = numpy.asarray([0]) pvar = 0.0 - #print 'ellapsed 2 %.03f'%(time.time()-TS) + #print('ellapsed 2 %.03f'%(time.time()-TS)) return { 'ok':True, 'fill':fill, diff --git a/iocBoot/iocFPM/loadnp.py b/iocBoot/iocFPM/loadnp.py index adf1eed..e8a0487 100644 --- a/iocBoot/iocFPM/loadnp.py +++ b/iocBoot/iocFPM/loadnp.py @@ -12,7 +12,7 @@ class Device(object): def __init__(self, rec, fname): if not fname: return - print 'Load', fname,'into',rec.NAME + print('Load', fname,'into',rec.NAME) data = numpy.load(fname) assert len(data.shape)==1, 'only 1D supported' val = rec.field('VAL') diff --git a/iocBoot/iocFPM/st.cmd b/iocBoot/iocFPM/st.cmd index 9a57d43..1781d5c 100755 --- a/iocBoot/iocFPM/st.cmd +++ b/iocBoot/iocFPM/st.cmd @@ -1,4 +1,4 @@ -#!./bin/linux-x86/softIocPy +#!../../bin/linux-x86_64/softIocPy3.6 epicsEnvSet("ENGINEER","mdavidsaver") epicsEnvSet("LOCATION","740") diff --git a/iocBoot/ioccaputlog/st.cmd b/iocBoot/ioccaputlog/st.cmd index dd9250a..4c183d0 100755 --- a/iocBoot/ioccaputlog/st.cmd +++ b/iocBoot/ioccaputlog/st.cmd @@ -1,4 +1,4 @@ -#!../../bin/linux-x86/softIocPy2.6 +#!../../bin/linux-x86_64/softIocPy3.6 < envPaths diff --git a/logApp/src/inotifyy.py b/logApp/src/inotifyy.py index 1b6180b..7ec0d61 100644 --- a/logApp/src/inotifyy.py +++ b/logApp/src/inotifyy.py @@ -14,7 +14,7 @@ def decodeMask(mask): ret = [] - for k,v in _flags.iteritems(): + for k,v in _flags.items(): if mask&v: ret.append(k) return '%s %s'%(hex(mask),ret)