update doc

This commit is contained in:
Michael Davidsaver
2018-11-04 16:25:24 -08:00
parent 4b05477417
commit dcf81c3744
7 changed files with 96 additions and 220 deletions

View File

@ -31,7 +31,6 @@ _dbapi_SRCS += pyDevSupCommon_registerRecordDeviceDriver.cpp
_dbapi_LIBS += $(EPICS_BASE_IOC_LIBS) _dbapi_LIBS += $(EPICS_BASE_IOC_LIBS)
PY += devsup/__init__.py PY += devsup/__init__.py
PY += devsup/_nullapi.py
PY += devsup/db.py PY += devsup/db.py
PY += devsup/dset.py PY += devsup/dset.py
PY += devsup/hooks.py PY += devsup/hooks.py

View File

@ -445,25 +445,28 @@ static PyObject *pyField_len(pyField *self)
static PyMethodDef pyField_methods[] = { static PyMethodDef pyField_methods[] = {
{"name", (PyCFunction)pyField_name, METH_NOARGS, {"name", (PyCFunction)pyField_name, METH_NOARGS,
"Return Names (\"record\",\"field\")"}, "name() -> (recname, fldname)\n"},
{"fieldinfo", (PyCFunction)pyField_fldinfo, METH_NOARGS, {"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, {"getval", (PyCFunction)pyField_getval, METH_NOARGS,
"Returns scalar version of field value"}, "getval() -> object\n"},
{"putval", (PyCFunction)pyField_putval, METH_VARARGS, {"putval", (PyCFunction)pyField_putval, METH_VARARGS,
"Sets field value from a scalar"}, "putval(object)\n"},
{"getarray", (PyCFunction)pyField_getarray, METH_NOARGS, {"getarray", (PyCFunction)pyField_getarray, METH_NOARGS,
"getarray() -> numpy.ndarray\n"
"Return a numpy ndarray refering to this field for in-place operations."}, "Return a numpy ndarray refering to this field for in-place operations."},
{"getarraylen", (PyCFunction)pyField_getlen, METH_NOARGS, {"getarraylen", (PyCFunction)pyField_getlen, METH_NOARGS,
"getarraylen() -> int\n"
"Return current number of valid elements for array fields."}, "Return current number of valid elements for array fields."},
{"putarraylen", (PyCFunction)pyField_setlen, METH_VARARGS, {"putarraylen", (PyCFunction)pyField_setlen, METH_VARARGS,
"putarraylen(int)\n"
"Set number of valid elements for array fields."}, "Set number of valid elements for array fields."},
{"getTime", (PyCFunction)pyField_getTime, METH_NOARGS, {"getTime", (PyCFunction)pyField_getTime, METH_NOARGS,
"Return link target timestamp as a tuple (sec, nsec)."}, "getTime() -> (sec, nsec)."},
{"getAlarm", (PyCFunction)pyField_getAlarm, METH_NOARGS, {"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, {"__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} {NULL, NULL, 0, NULL}
}; };

View File

@ -293,23 +293,32 @@ static PyObject *pyRecord_exit(pyRecord *self, PyObject *args)
static PyMethodDef pyRecord_methods[] = { static PyMethodDef pyRecord_methods[] = {
{"name", (PyCFunction)pyRecord_name, METH_NOARGS, {"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", (PyCFunction)pyRecord_rtype, METH_NOARGS,
"rtype() -> str\n"
"Return record type name string"}, "Return record type name string"},
{"isPyRecord", (PyCFunction)pyRecord_ispyrec, METH_NOARGS, {"isPyRecord", (PyCFunction)pyRecord_ispyrec, METH_NOARGS,
"isPyRecord() -> bool\n"
"Is this record using Python Device."}, "Is this record using Python Device."},
{"info", (PyCFunction)pyRecord_info, METH_VARARGS, {"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", (PyCFunction)pyRecord_infos, METH_NOARGS,
"infos() -> {'name':'value'}\n"
"Return a dictionary of all infos for this record."}, "Return a dictionary of all infos for this record."},
{"setSevr", (PyCFunction)pyRecord_setSevr, METH_VARARGS|METH_KEYWORDS, {"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!"}, "Set alarm new alarm severity/status. Record must be locked!"},
{"setTime", (PyCFunction)pyRecord_setTime, METH_VARARGS, {"setTime", (PyCFunction)pyRecord_setTime, METH_VARARGS,
"Set record timestamp if TSE==-2. Record must be locked!"}, "Set record timestamp if TSE==-2. Record must be locked!"},
{"scan", (PyCFunction)pyRecord_scan, METH_VARARGS|METH_KEYWORDS, {"scan", (PyCFunction)pyRecord_scan, METH_VARARGS|METH_KEYWORDS,
"scan(sync=False)\nScan this record. If sync is False then" "scan(sync=False, reason=None, force=0)\n"},
"a scan request is queued. If sync is True then the record"
"is scannined immidately on the current thread."},
{"asyncStart", (PyCFunction)pyRecord_asyncStart, METH_NOARGS, {"asyncStart", (PyCFunction)pyRecord_asyncStart, METH_NOARGS,
"Begin an asynchronous action. Record must be locked!"}, "Begin an asynchronous action. Record must be locked!"},
{"asyncFinish", (PyCFunction)pyRecord_asyncFinish, METH_VARARGS|METH_KEYWORDS, {"asyncFinish", (PyCFunction)pyRecord_asyncFinish, METH_VARARGS|METH_KEYWORDS,

View File

@ -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 = {}

View File

@ -260,6 +260,76 @@ class Record(_dbapi._Record):
super(Record, self).setTime(sec, nsec) 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): def __getattr__(self, name):
try: try:
F = self.field(name) F = self.field(name)

View File

@ -42,7 +42,7 @@ def initHook(state):
@initHook("AfterIocRunning") @initHook("AfterIocRunning")
def myfn(): def myfn():
# do stuff pass
""" """
def _add(fn): def _add(fn):
addHook(state, fn) addHook(state, fn)

View File

@ -108,7 +108,7 @@ In somefile.c ::
PyMODINIT_FUNC init_myextname(void) PyMODINIT_FUNC init_myextname(void)
Installing for several Python versions Installing for several Python versions
------------------------------------ --------------------------------------
The recipe for building and installing the pyDevSup module The recipe for building and installing the pyDevSup module
for several python version side by side is :: for several python version side by side is ::