update doc
This commit is contained in:
@ -31,7 +31,6 @@ _dbapi_SRCS += pyDevSupCommon_registerRecordDeviceDriver.cpp
|
||||
_dbapi_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
PY += devsup/__init__.py
|
||||
PY += devsup/_nullapi.py
|
||||
PY += devsup/db.py
|
||||
PY += devsup/dset.py
|
||||
PY += devsup/hooks.py
|
||||
|
@ -445,25 +445,28 @@ static PyObject *pyField_len(pyField *self)
|
||||
|
||||
static PyMethodDef pyField_methods[] = {
|
||||
{"name", (PyCFunction)pyField_name, METH_NOARGS,
|
||||
"Return Names (\"record\",\"field\")"},
|
||||
"name() -> (recname, fldname)\n"},
|
||||
{"fieldinfo", (PyCFunction)pyField_fldinfo, METH_NOARGS,
|
||||
"Field type info\nReturn (type, size, #elements"},
|
||||
"fieldinfo() -> (dbf, elem_size, elem_count"},
|
||||
{"getval", (PyCFunction)pyField_getval, METH_NOARGS,
|
||||
"Returns scalar version of field value"},
|
||||
"getval() -> object\n"},
|
||||
{"putval", (PyCFunction)pyField_putval, METH_VARARGS,
|
||||
"Sets field value from a scalar"},
|
||||
"putval(object)\n"},
|
||||
{"getarray", (PyCFunction)pyField_getarray, METH_NOARGS,
|
||||
"getarray() -> numpy.ndarray\n"
|
||||
"Return a numpy ndarray refering to this field for in-place operations."},
|
||||
{"getarraylen", (PyCFunction)pyField_getlen, METH_NOARGS,
|
||||
"getarraylen() -> int\n"
|
||||
"Return current number of valid elements for array fields."},
|
||||
{"putarraylen", (PyCFunction)pyField_setlen, METH_VARARGS,
|
||||
"putarraylen(int)\n"
|
||||
"Set number of valid elements for array fields."},
|
||||
{"getTime", (PyCFunction)pyField_getTime, METH_NOARGS,
|
||||
"Return link target timestamp as a tuple (sec, nsec)."},
|
||||
"getTime() -> (sec, nsec)."},
|
||||
{"getAlarm", (PyCFunction)pyField_getAlarm, METH_NOARGS,
|
||||
"Return link target alarm condtions as a tuple (severity, status)."},
|
||||
"getAlarm() -> (severity, status)."},
|
||||
{"__len__", (PyCFunction)pyField_len, METH_NOARGS,
|
||||
"Maximum number of elements storable in this field"},
|
||||
"Maximum number of elements storable in this field."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
@ -293,23 +293,32 @@ static PyObject *pyRecord_exit(pyRecord *self, PyObject *args)
|
||||
|
||||
static PyMethodDef pyRecord_methods[] = {
|
||||
{"name", (PyCFunction)pyRecord_name, METH_NOARGS,
|
||||
"Return record name string"},
|
||||
"name() -> str\n\n"
|
||||
"Record name. ::\n"
|
||||
"\n"
|
||||
" R = getRecord(\"my:record:name\")\n"
|
||||
" assert R.name()==\"my:record:name\"\n"},
|
||||
{"rtype", (PyCFunction)pyRecord_rtype, METH_NOARGS,
|
||||
"rtype() -> str\n"
|
||||
"Return record type name string"},
|
||||
{"isPyRecord", (PyCFunction)pyRecord_ispyrec, METH_NOARGS,
|
||||
"isPyRecord() -> bool\n"
|
||||
"Is this record using Python Device."},
|
||||
{"info", (PyCFunction)pyRecord_info, METH_VARARGS,
|
||||
"Lookup info name\ninfo(name, def=None)"},
|
||||
"info(key [,default]) -> str\n"
|
||||
"Lookup info by name\n"
|
||||
":rtype: str\n"
|
||||
":throws: KeyError\n"},
|
||||
{"infos", (PyCFunction)pyRecord_infos, METH_NOARGS,
|
||||
"infos() -> {'name':'value'}\n"
|
||||
"Return a dictionary of all infos for this record."},
|
||||
{"setSevr", (PyCFunction)pyRecord_setSevr, METH_VARARGS|METH_KEYWORDS,
|
||||
"setSevr(sevr=INVALID_ALARM, stat=COMM_ALARM)\n"
|
||||
"Set alarm new alarm severity/status. Record must be locked!"},
|
||||
{"setTime", (PyCFunction)pyRecord_setTime, METH_VARARGS,
|
||||
"Set record timestamp if TSE==-2. Record must be locked!"},
|
||||
{"scan", (PyCFunction)pyRecord_scan, METH_VARARGS|METH_KEYWORDS,
|
||||
"scan(sync=False)\nScan this record. If sync is False then"
|
||||
"a scan request is queued. If sync is True then the record"
|
||||
"is scannined immidately on the current thread."},
|
||||
"scan(sync=False, reason=None, force=0)\n"},
|
||||
{"asyncStart", (PyCFunction)pyRecord_asyncStart, METH_NOARGS,
|
||||
"Begin an asynchronous action. Record must be locked!"},
|
||||
{"asyncFinish", (PyCFunction)pyRecord_asyncFinish, METH_VARARGS|METH_KEYWORDS,
|
||||
|
@ -1,205 +0,0 @@
|
||||
|
||||
class _Record(object):
|
||||
"""Handle for record operations
|
||||
|
||||
r = _Record("rec:name")
|
||||
"""
|
||||
|
||||
def __init__(self, rec):
|
||||
pass
|
||||
def name(self):
|
||||
"""Record name string.
|
||||
|
||||
>>> R = getRecord("my:record:name")
|
||||
>>> R.name()
|
||||
"my:record:name"
|
||||
"""
|
||||
def rtype(self):
|
||||
"""Record type name string.
|
||||
|
||||
>>> R = getRecord("my:record:name")
|
||||
>>> R.type()
|
||||
"longin"
|
||||
"""
|
||||
def isPyRecord(self):
|
||||
"""Is this record using Python device support.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
def info(self, key):
|
||||
"""info(key [,default])
|
||||
|
||||
:rtype: str
|
||||
:throws: KeyError
|
||||
|
||||
Lookup record info tag. If no default
|
||||
is provided then an exception is raised
|
||||
if the info key does not exist.
|
||||
"""
|
||||
def infos(self):
|
||||
"""Return a dictionary of all info tags
|
||||
for this record
|
||||
"""
|
||||
|
||||
def setSevr(self, sevr=3, stat=15):
|
||||
"""setSevr(sevr=INVALID_ALARM, stat=COMM_ALARM)
|
||||
|
||||
Signal a new alarm condition. The effect of this
|
||||
call depends on the current alarm condition.
|
||||
|
||||
See :c:func:`recGblSetSevr` in EPICS Base.
|
||||
"""
|
||||
|
||||
def scan(self, sync=False, reason=None, force=0):
|
||||
"""Scan this record.
|
||||
|
||||
:param sync: scan in current thread (``True``), or queue to a worker (``False``).
|
||||
:param reason: Reason object passed to :meth:`process <DeviceSupport.process>` (sync=True only)
|
||||
:param force: Record processing condtion (0=Passive, 1=Force, 2=I/O Intr)
|
||||
:throws: ``RuntimeError`` when ``sync=True``, but ``force`` prevents scanning.
|
||||
|
||||
If ``sync`` is False then a scan request is queued to run in another thread..
|
||||
If ``sync`` is True then the record is scanned immediately on the current thread.
|
||||
|
||||
For ``reason`` argument must be used in conjunction with ``sync=True``
|
||||
on records with Python device support. This provides a means
|
||||
of providing extra contextual information to the record's
|
||||
:meth:`process <DeviceSupport.process>` method.
|
||||
|
||||
``force`` is used to decide if the record will actually be processed,
|
||||
``force=0`` will only process records with SCAN=Passive.
|
||||
``force=1`` will process any record if at all possible.
|
||||
``force=2`` will only process records with Python device support and
|
||||
SCAN=I/O Intr.
|
||||
|
||||
.. important::
|
||||
It is **never** safe to use ``sync=True`` while holding record locks,
|
||||
including from within a *process* method.
|
||||
"""
|
||||
|
||||
def asyncStart(self):
|
||||
"""Start asynchronous processing
|
||||
|
||||
This method may be called from a device support
|
||||
:meth:`process <DeviceSupport.process>` method
|
||||
to indicate that processing will continue
|
||||
later.
|
||||
|
||||
.. important::
|
||||
This method is **only** safe to call within a *process* method.
|
||||
"""
|
||||
def asyncFinish(self, reason=None):
|
||||
"""Indicate that asynchronous processing can complete
|
||||
|
||||
Similar to :meth:`scan`. Used to conclude asynchronous
|
||||
process started with :meth:`asyncStart`.
|
||||
|
||||
Processing is completed on the current thread.
|
||||
|
||||
.. important::
|
||||
This method should **never** be called within
|
||||
a :meth:`process <DeviceSupport.process>` method,
|
||||
or any other context where a Record lock is held.
|
||||
Doing so will result in a deadlock.
|
||||
|
||||
Typically a *reason* will be passed to *process* as a way
|
||||
of indicating that this is the completion of an async action. ::
|
||||
|
||||
AsyncDone = object()
|
||||
class MySup(object):
|
||||
def process(record, reason):
|
||||
if reason is AsyncDone:
|
||||
record.VAL = ... # store result
|
||||
else:
|
||||
threading.Timer(1.0, record.asyncFinish, kwargs={'reason':AsyncDone})
|
||||
record.asyncStart()
|
||||
"""
|
||||
|
||||
class _Field(object):
|
||||
"""Handle for field operations
|
||||
|
||||
f = Field("rec:name.HOPR")
|
||||
|
||||
Field objects implement the buffer protocol.
|
||||
"""
|
||||
def __init__(self, fld):
|
||||
pass
|
||||
def name(self):
|
||||
"""Fetch the record and field names.
|
||||
|
||||
>>> FLD = getRecord("rec").field("FLD")
|
||||
>>> FLD.name()
|
||||
("rec", "FLD")
|
||||
"""
|
||||
def fieldinfo(self):
|
||||
"""(type, size, #elements) = fieldinfo()
|
||||
|
||||
Type is DBF type code
|
||||
size is number of bytes to start a single element
|
||||
#elements is the maximum number of elements the field can hold
|
||||
"""
|
||||
|
||||
def getval(self):
|
||||
"""Fetch the current field value as a scalar or numpy.ndarray.
|
||||
|
||||
:rtype: int, float, str, or ndarray
|
||||
|
||||
Returned type depends of field DBF type.
|
||||
An ``int`` is returned for CHAR, SHORT, LONG, and ENUM.
|
||||
A ``float`` is returned for FLOAT and DOUBLE.
|
||||
A ``str`` is returned for STRING.
|
||||
A ``numpy.ndarray`` is returned for array fields.
|
||||
This array is read-only and has the size of the present valid values.
|
||||
|
||||
.. important::
|
||||
It is only safe to read this ndarray while the record
|
||||
lock is held (ie within :meth:`process <DeviceSupport.process>`).
|
||||
"""
|
||||
|
||||
def putval(self, val):
|
||||
"""Update the field value
|
||||
|
||||
Must be an Int, Float, str, or numpy.ndarray.
|
||||
Strings will be truncated to 39 characters.
|
||||
Arrays must have a size less than or equal to the max element count.
|
||||
Arrays are converted as necessary to the field's native type.
|
||||
"""
|
||||
|
||||
def getarray(self):
|
||||
"""Return a numpy ndarray refering to this field for in-place operations.
|
||||
|
||||
The dtype of the ndarray will correspond to the field's DBF type.
|
||||
Its size will be the **maximum** number of elements.
|
||||
|
||||
.. important::
|
||||
It is only safe to read or write to this ndarray while the record
|
||||
lock is held (ie within :meth:`process <DeviceSupport.process>`).
|
||||
"""
|
||||
|
||||
def getarraylen(self):
|
||||
"""Return the number of active elements for the field.
|
||||
|
||||
>>> F = Field(...)
|
||||
>>> assert len(F)>=F.getarraylen()
|
||||
"""
|
||||
|
||||
def putarraylen(self, len):
|
||||
"""Set the number of active elements in field's array.
|
||||
|
||||
Requires that the underlying field be an array.
|
||||
Must be greater than one and less than or equal to the maximum length of the field.
|
||||
"""
|
||||
|
||||
def getAlarm(self):
|
||||
"""Returns a tuple (severity, status) with the condition of the linked field.
|
||||
|
||||
Only works for fields of type DBF_INLINK.
|
||||
"""
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the maximum number of elements which may be stored in the field.
|
||||
|
||||
This is always 1 for scalar fields.
|
||||
"""
|
||||
|
||||
_hooks = {}
|
@ -260,6 +260,76 @@ class Record(_dbapi._Record):
|
||||
|
||||
super(Record, self).setTime(sec, nsec)
|
||||
|
||||
def scan(self, *args, **kws):
|
||||
"""scan(sync=False, reason=None, force=0)
|
||||
Scan this record.
|
||||
|
||||
:param sync: scan in current thread (``True``), or queue to a worker (``False``).
|
||||
:param reason: Reason object passed to :meth:`process <DeviceSupport.process>` (sync=True only)
|
||||
:param force: Record processing condtion (0=Passive, 1=Force, 2=I/O Intr)
|
||||
:throws: ``RuntimeError`` when ``sync=True``, but ``force`` prevents scanning.
|
||||
|
||||
If ``sync`` is False then a scan request is queued to run in another thread..
|
||||
If ``sync`` is True then the record is scanned immediately on the current thread.
|
||||
|
||||
For ``reason`` argument must be used in conjunction with ``sync=True``
|
||||
on records with Python device support. This provides a means
|
||||
of providing extra contextual information to the record's
|
||||
:meth:`process <DeviceSupport.process>` method.
|
||||
|
||||
``force`` is used to decide if the record will actually be processed,
|
||||
``force=0`` will only process records with SCAN=Passive.
|
||||
``force=1`` will process any record if at all possible.
|
||||
``force=2`` will only process records with Python device support and
|
||||
SCAN=I/O Intr.
|
||||
|
||||
.. important::
|
||||
It is **never** safe to use ``sync=True`` while holding record locks,
|
||||
including from within a *process* method.
|
||||
"""
|
||||
return _dbapi._Record.scan(self, *args, **kws)
|
||||
|
||||
def asyncStart(self):
|
||||
"""Start asynchronous processing
|
||||
|
||||
This method may be called from a device support
|
||||
:meth:`process <DeviceSupport.process>` method
|
||||
to indicate that processing will continue
|
||||
later.
|
||||
|
||||
.. important::
|
||||
This method is **only** safe to call within a *process* method.
|
||||
"""
|
||||
return _dbapi._Record.asyncStart(self)
|
||||
|
||||
def asyncFinish(self, reason=None):
|
||||
"""Indicate that asynchronous processing can complete
|
||||
|
||||
Similar to :meth:`scan`. Used to conclude asynchronous
|
||||
process started with :meth:`asyncStart`.
|
||||
|
||||
Processing is completed on the current thread.
|
||||
|
||||
.. important::
|
||||
This method should **never** be called within
|
||||
a :meth:`process <DeviceSupport.process>` method,
|
||||
or any other context where a Record lock is held.
|
||||
Doing so will result in a deadlock.
|
||||
|
||||
Typically a *reason* will be passed to *process* as a way
|
||||
of indicating that this is the completion of an async action. ::
|
||||
|
||||
AsyncDone = object()
|
||||
class MySup(object):
|
||||
def process(record, reason):
|
||||
if reason is AsyncDone:
|
||||
record.VAL = ... # store result
|
||||
else:
|
||||
threading.Timer(1.0, record.asyncFinish, kwargs={'reason':AsyncDone})
|
||||
record.asyncStart()
|
||||
"""
|
||||
return _dbapi._Record.asyncStart(self, reason=reason)
|
||||
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
F = self.field(name)
|
||||
|
@ -42,7 +42,7 @@ def initHook(state):
|
||||
|
||||
@initHook("AfterIocRunning")
|
||||
def myfn():
|
||||
# do stuff
|
||||
pass
|
||||
"""
|
||||
def _add(fn):
|
||||
addHook(state, fn)
|
||||
|
@ -108,7 +108,7 @@ In somefile.c ::
|
||||
PyMODINIT_FUNC init_myextname(void)
|
||||
|
||||
Installing for several Python versions
|
||||
------------------------------------
|
||||
--------------------------------------
|
||||
|
||||
The recipe for building and installing the pyDevSup module
|
||||
for several python version side by side is ::
|
||||
|
Reference in New Issue
Block a user