summaryrefslogtreecommitdiff
diff options
authorAndrius Merkys <merkys@debian.org>2026-02-06 04:06:38 -0500
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2026-02-06 16:48:57 +0000
commit4970b935cd94cd284516ba6d94f5b70689beeb65 (patch)
tree2a17a4b07a9f902123ab9406d5baef99a766648f
parent062621afd9dfb5a93f323a5f7a6f6489ada8ccad (diff)
Imported using git-ubuntu import.
Notes
Notes: * New upstream version 3.5.9+ds
-rw-r--r--.github/workflows/test-with-conda.yml4
-rw-r--r--README.rst8
-rw-r--r--debian/changelog6
-rw-r--r--debian/control2
-rw-r--r--doc/_templates/indexsidebar.html24
-rw-r--r--doc/_templates/layout.html20
-rw-r--r--doc/advanced.rst6
-rw-r--r--doc/conf.py206
-rw-r--r--doc/index.rst34
-rw-r--r--doc/installation.rst194
-rw-r--r--doc/overview.rst20
-rw-r--r--doc/wx.rst2
-rw-r--r--epics/__init__.py2
-rw-r--r--epics/alarm.py3
-rwxr-xr-xepics/ca.py11
-rw-r--r--epics/dbr.py3
-rw-r--r--epics/device.py1
-rw-r--r--epics/devices/ad_mca.py3
-rw-r--r--epics/devices/ad_perkinelmer.py1
-rw-r--r--epics/devices/mca.py3
-rwxr-xr-xepics/devices/struck.py1
-rwxr-xr-xepics/devices/xspress3.py3
-rwxr-xr-xepics/wx/motordetailframe.py3
-rwxr-xr-xepics/wx/motorpanel.py2
-rw-r--r--epics/wx/wxlib.py30
-rwxr-xr-xepics/wx/wxutils.py8
-rw-r--r--pyproject.toml6
-rw-r--r--scripts/mpanel.py7
-rwxr-xr-xscripts/wxfloat_probe.py66
29 files changed, 289 insertions, 390 deletions
diff --git a/.github/workflows/test-with-conda.yml b/.github/workflows/test-with-conda.yml
index d45f281..c143c47 100644
--- a/.github/workflows/test-with-conda.yml
+++ b/.github/workflows/test-with-conda.yml
@@ -1,4 +1,4 @@
-name: Test with Conda, Py3.9 to 3.13
+name: Test with Conda, Py3.10 to 3.14
on: [push]
@@ -9,7 +9,7 @@ jobs:
max-parallel: 5
fail-fast: false
matrix:
- python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
defaults:
run:
shell: bash -l {0}
diff --git a/README.rst b/README.rst
index 43b9b0f..2b2f118 100644
--- a/README.rst
+++ b/README.rst
@@ -2,13 +2,7 @@ PyEpics: Epics Channel Access for Python
==============================================
.. image:: https://github.com/pyepics/pyepics/actions/workflows/test-with-conda.yml/badge.svg
- :target: https://github.com/pyepics/pyepics/actions/workflows/test-with-conda.yml/
-
-.. image:: https://github.com/pyepics/pyepics/actions/workflows/test-python38.yml/badge.svg
- :target: https://github.com/pyepics/pyepics/actions/workflows/test-python38.yml/
-
-.. image:: https://codecov.io/gh/pyepics/pyepics/branch/master/graph/badge.svg
- :target: https://codecov.io/gh/pyepics/pyepics
+ :target: https://github.com/pyepics/pyepics/actions/workflows/test-with-conda.yml/
.. image:: https://img.shields.io/pypi/v/pyepics.svg
:target: https://pypi.org/project/pyepics
diff --git a/debian/changelog b/debian/changelog
index 17a88f9..eae8d47 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-pyepics (3.5.9+ds-1) unstable; urgency=medium
+
+ * New upstream version 3.5.9+ds
+
+ -- Andrius Merkys <merkys@debian.org> Fri, 06 Feb 2026 04:06:38 -0500
+
python-pyepics (3.5.8+ds-1) unstable; urgency=medium
* Team upload.
diff --git a/debian/control b/debian/control
index 79d0f0a..9593585 100644
--- a/debian/control
+++ b/debian/control
@@ -19,6 +19,8 @@ Build-Depends:
python3-setuptools,
python3-setuptools-scm,
python3-sphinx <!nodoc>,
+ python3-sphinx-copybutton <!nodoc>,
+ python3-sphinxcontrib-video <!nodoc>,
python3-wxgtk4.0,
Standards-Version: 4.7.2
Homepage: https://pyepics.github.io/pyepics/
diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html
index 1b481f6..30d1f32 100644
--- a/doc/_templates/indexsidebar.html
+++ b/doc/_templates/indexsidebar.html
@@ -1,12 +1,24 @@
<h3>Download</h3>
-<p>Current version: <b>{{ release }}</b></p>
+<ul>
+ <li>Current version: <b>{{ release }}</b></li>
+ <li>Install: <tt> pip install pyepics</tt></li>
+ <li>Develop: <a href="https://github.com/pyepics/pyepics/">github.com</a></li>
+ </ul>
-<p>
- Install: &nbsp; <tt> pip install pyepics</tt>
<p>
- Develop: &nbsp; <a href="https://github.com/pyepics/pyepics/">github.com</a>
-<br>
+<h3>Contents</h3>
-<p>
+<ul>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('installation') }}"> Install</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('overview') }}"> Overview</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('pv') }}"> Epics PVs</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('ca') }}"> CA module</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('arrays') }}"> Working with Array Data</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('devices') }}"> Devices</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('alarm') }}"> Alarms</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('autosave') }}"> Autosave</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('wx') }}"> wx widgets for PVs</a></li>
+ <li>&nbsp; &nbsp;<a href="{{ pathto('advanced') }}"> Advanced Topics</a></li>
+</ul>
diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html
index 5a1c9c2..0b6c2b2 100644
--- a/doc/_templates/layout.html
+++ b/doc/_templates/layout.html
@@ -1,18 +1,5 @@
{% extends "!layout.html" %}
-{% block rootrellink %}
- <li>[<a href="{{ pathto('installation') }}">install</a></li>
- <li>|<a href="{{ pathto('overview') }}">overview</a></li>
- <li>|<a href="{{ pathto('pv') }}">pv</a></li>
- <li>|<a href="{{ pathto('ca') }}">ca</a></li>
- <li>|<a href="{{ pathto('arrays') }}">arrays</a></li>
- <li>|<a href="{{ pathto('devices') }}">devices</a></li>
- <li>|<a href="{{ pathto('alarm') }}">alarm</a></li>
- <li>|<a href="{{ pathto('autosave') }}">autosave</a></li>
- <li>|<a href="{{ pathto('wx') }}">wx</a></li>
- <li>|<a href="{{ pathto('advanced') }}">advanced</a>]</li>
-{% endblock %}
-
-{% block relbar1 %}
+{%- block relbar1 %}
<div style="background-color: #E7F0F3; text-align: left; padding: 8px 4px 8px 4px">
<font size=+3><a href="{{ pathto('index') }}">
<img src="{{pathto("_static/pyepics.png", 1) }}" height=50 border="0" alt="pyepics"/>
@@ -21,8 +8,3 @@
</div>
{{ super() }}
{% endblock %}
-
-
-{# put the sidebar before the body #}
-{% block sidebar1 %}{{ sidebar() }}{% endblock %}
-{% block sidebar2 %}{% endblock %}
diff --git a/doc/advanced.rst b/doc/advanced.rst
index 4e1d3a8..415fa2d 100644
--- a/doc/advanced.rst
+++ b/doc/advanced.rst
@@ -101,7 +101,7 @@ cause.
Creating a `PV` object (using any of :class:`pv.PV`, or :func:`pv.get_pv`, or
:func:`epics.caget`) will automatically use connection and event callbacks in
-an attempt to keep the `PV` alive and up-to-date during the seesion. This is
+an attempt to keep the `PV` alive and up-to-date during the session. This is
usually an advantage, as you don't need to explicitly deal with many aspects of
Channel Access. But creating a `PV` does request some network traffic, and the
`PV` will not be "fully connected" and ready to do a :meth:`PV.get` until all
@@ -225,7 +225,7 @@ In tests with 1000 PVs, looping with :func:`epics.caget_many` took about
seconds.
To be clear, it is **connecting** to Epics PVs that is expensive, not the
-retreiving of data from connected PVs. You can lower the connection
+retrieving of data from connected PVs. You can lower the connection
expense by not retaining the connection or creating monitors on the PVs,
but if you are going to re-use the PVs, that savings will be lost quickly.
In short, use Method 1 over :func:`epics.caget_many` unless you've benchmarked
@@ -254,7 +254,7 @@ in order for events to be processed. The simplest way to do this is with
Unfortunately, the :meth:`time.sleep` method is not a very high-resolution
clock, with typical resolutions of 1 to 10 ms, depending on the system.
Thus, even though events will be asynchronously generated and epics with
-pre-emptive callbacks does not *require* :meth:`epics.ca.pend_event` or
+preemptive callbacks does not *require* :meth:`epics.ca.pend_event` or
:meth:`epics.ca.poll` to be run, better performance may be achieved with an event
loop of::
diff --git a/doc/conf.py b/doc/conf.py
index 8c8a824..2b9e75e 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -1,205 +1,41 @@
# -*- coding: utf-8 -*-
-#
-# epics documentation build configuration file, created by
-# sphinx-quickstart on Fri Feb 12 01:10:08 2010.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
import sys, os
+from packaging.version import parse as version_parse
+import epics
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.append(os.path.abspath('.'))
-
-# -- General configuration -----------------------------------------------------
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.extlinks',
- 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'numpydoc']
-
-# Add any paths that contain templates here, relative to this directory.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.mathjax',
+ 'sphinx.ext.napoleon', 'sphinxcontrib.video',
+ 'sphinx_copybutton', 'numpydoc']
templates_path = ['_templates']
-# The suffix of source filenames.
-source_suffix = {'.rst': 'restructuredtext'}
-
-# The encoding of source files.
-#source_encoding = 'utf-8'
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'epics'
-copyright = u'2021, Matthew Newville'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-try:
- import epics
- release = epics.__version__
- if '-' in release:
- a, b = release.split('-', 1)
- release = a
- if '_' in release:
- a, b = release.split('_', 1)
- release = a
- # The full version, including alpha/beta/rc tags.
-except ImportError:
- release = '3.X.Y'
+project = "PyEpics"
+copyright = "2025, Matthew Newville, The University of Chicago"
-print( 'Building Docs for EPICS version %s / Python version %s ' % (release, sys.version))
+html_title = "Epics Channel Access for Python"
+html_short_title = "PyEpics"
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
+release = version_parse(epics.__version__).base_version
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of documents that shouldn't be included in the build.
-#unused_docs = []
-
-# List of directories, relative to source directory, that shouldn't be searched
-# for source files.
+source_suffix = {'.rst': 'restructuredtext'}
exclude_trees = ['_build']
+default_role = None
+source_encoding = 'utf-8'
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-# show_authors = True
-
-# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
+master_doc = 'index'
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. Major themes that come with
-# Sphinx are currently 'default' and 'sphinxdoc'.
-
-#####
-html_theme_path = ['sphinx/theme']
-html_theme = 'epicsdoc'
-#####
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-html_title = 'Epics Channel Access for Python'
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-html_short_title = 'PyEpics'
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
+html_theme_path = ['sphinx_theme']
+html_theme = 'bizstyle'
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
+html_sidebars = {
+ 'index': ["indexsidebar.html", "sourcelink.html", "searchbox.html"],
+ "**": [ "localtoc.html", "relations.html", "sourcelink.html", "searchbox.html"]
+}
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-# html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-html_sidebars = {'index': ['indexsidebar.html','searchbox.html']}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-# html_use_modindex = True
-html_use_modindex = False
-
-# If false, no index is generated.
+html_domain_indices = False
html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
html_show_sourcelink = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = ''
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'epicsdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'epics.tex', u'PyEpics: Python Epics Channel Access',
- u'Matthew Newville', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-latex_logo = '_static/pyepics.png'
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-# latex_use_modindex = True
-latex_use_modindex = False
diff --git a/doc/index.rst b/doc/index.rst
index 1dbd38d..d5ea97f 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -11,26 +11,24 @@ via the CA protocol. The package includes a thin and fairly complete layer
over the lowest-level Channel Access library in the :mod:`ca` module, and
higher level abstractions built on top of this basic functionality.
-The package includes a very simple interface to CA similar to the Unix
-command-line tools with functions :meth:`epics.caget`, :meth:`epics.caput`,
-:meth:`epics.cainfo`, and :meth:`epics.camonitor`. For an object-oriented
-interface, there is also a :class:`pv.PV` class which represents an Epics
-Process Variable as a full-featured and easy-to-use Python object.
-Additional modules provide higher-level programming support to CA,
-including grouping related PVs into a :class:`device.Device` (with a number
-of predefined devices ready to use), for creating alarms in
-:class:`alarm.Alarm`, and for saving PVs values in the :mod:`autosave`
-module. There is also support for conveniently using epics PVs to wxPython
-widgets in the :mod:`wx` module, and some support for using PyQt widgets in
-the :mod:`qt` module.
-
------------
-
-See also: Some `applications <https://pyepics.github.io/epicsapps/>`_ built
-with pyepics that are available at `https://github.com/pyepics/epicsapps/
+The package includes a simple interface to CA similar to the Unix
+command-line tools with functions :meth:`epics.caget`,
+:meth:`epics.caput`, :meth:`epics.cainfo`, and
+:meth:`epics.camonitor`. For an object-oriented interface, there is a
+:class:`pv.PV` class which represents an Epics Process Variable as a
+full-featured and convenient Python object. Additional modules
+provide higher-level programming support to CA, including grouping
+related PVs into a :class:`device.Device` (with a number of predefined
+devices ready to use), for creating alarms in :class:`alarm.Alarm`,
+and for saving PVs values in the :mod:`autosave` module. There is
+also support for conveniently using epics PVs to wxPython widgets in
+the :mod:`wx` module, and some support for using PyQt widgets in the
+:mod:`qt` module.
+
+Some `applications <https://pyepics.github.io/epicsapps/>`_ built with
+pyepics that are available at `https://github.com/pyepics/epicsapps/
<https://github.com/pyepics/epicsapps/>`_.
-
-----------
.. toctree::
diff --git a/doc/installation.rst b/doc/installation.rst
index 7a75b8b..f938333 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -1,51 +1,14 @@
+.. _pyepics github repository: https://github.com/pyepics/pyepics
+.. _PyPi: https://pypi.python.org/pypi/pyepics/
+
+
====================================
Downloading and Installation
====================================
-Prerequisites
-~~~~~~~~~~~~~~~
-
-PyEpics works with Python version 3.8 and higher. At this writing,
-automated testing is done with versions 3.8 through 3.12,
-PyEpics may still work with Python 3.7 or even 3.6, but no testing or support
-is available for these.
-
-Pyepics is supported and regularly used on 64-bit Linux, 64-bit Windows, 64-bit
-Mac OSX with both Intel and Arm processors. PyEpics should also work on Linux
-with ARM processors including raspberry Pi and may still work on 32-bit Windows
-and Linux, though these systems are not tested regularly. As of this writing,
-automated testing is done only for Linux64.
-
-The EPICS Channel Access library Version 3.14.12 or higher is required for
-pyepics, and versions 7.0.4 or higher are strongly recommended. More
-specifically, pyepics requires the shared libraries *libca* and *libCom*
-(*libca.so* and *libCom.so* on Linux, *libca.dylib* and *libCom.dylib* on
-Mac OSX, or *ca.dll* and *Com.dll* on Windows) from *Epics Base*.
-
-For Linux64, Linux32, LinuxArm, Windows64, Windows32, Darwin64 (MacOS) on
-x86-64, and Darwin64 (MacOS) on arm64, pre-built versions of *libca* (and
-*libCom*) are provided and will be installed into the python packages directory
-and used by default. This means that you do not need to install Epics base
-libraries or any other packages to use pyepics. These libraries have been
-built with 3.16.2 or 7.0.7 - further details are given in the `clibs` folder of
-the source kit. For Epics experts who may want to use their own versions the
-*libca* from Epics base, instructions for how to do this are given below.
-
-The Python `numpy <https://numpy.org/>`_ module is highly recommended. and will
-be used to automatically convert between EPICS waveforms and numpy arrays if
-available.
-
-The `autosave` module requires the `pyparsing` package, which is widely
-available and often installed by default with many Python distributions.
-The `wx` module requires the `wxPython` package, and the `qt` module
-requires `PyQt` or `PySide`.
-
-Downloads and Installation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. _pyepics github repository: https://github.com/pyepics/pyepics
-.. _pyepics PyPi: https://pypi.python.org/pypi/pyepics/
+Installation
+~~~~~~~~~~~~~~~~~~~~~~~
The latest stable version of the pyepics package is |release| which can be
installed with::
@@ -53,62 +16,106 @@ installed with::
pip install pyepics
If you're using Anaconda Python, there are a few conda channels that
-provide the latest versions, but the version on `PyPI` should be considered
-the reference version. You can also download the source package, unpack
-it, and install with::
+provide the latest versions, but the version on `PyPI`_ should be considered
+the reference version.
- pip install .
+PyEpics |release| works with Python version 3.10 and higher. It may
+still work with older versions of Python, but no testing or support is
+available for these. At this writing, automated testing is done with
+versions 3.10 through 3.14 on 64-bit Linux, though Pyepics is
+supported and regularly used on 64-bit Linux, 64-bit Windows, 64-bit
+Mac OSX with both Intel and Arm processors. PyEpics should also work
+on Linux with ARM processors including raspberry Pi and may still work
+on 32-bit Windows and Linux, though these systems are not tested
+regularly.
+
+
+Prerequisites and Dependencies, Supported Systems
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Pyepics requires the EPICS Channel Access library from Epics Base
+Version 3.14.12 or higher. Using Epics Base 7.0.4 or higher is
+strongly recommended. More specifically, pyepics needs only to be
+able to find the shared libraries *libca* and *libCom* (*libca.so* and
+*libCom.so* on Linux, *libca.dylib* and *libCom.dylib* on Mac OSX, or
+*ca.dll* and *Com.dll* on Windows) from *Epics Base*.
+
+For Linux64, Linux32, LinuxArm, Windows64, Windows32, Darwin64 (MacOS)
+on x86-64, and Darwin64 (MacOS) on arm64, pre-built versions of
+*libca* (and *libCom*) are provided with pyepics. These will be
+installed with the python packages directory and will used by
+default. This means that you do not need to separately install Epics
+base libraries or any other packages to use pyepics. These libraries
+have been built with 3.16.2 or 7.0.7 - further details are given in
+the `clibs` folder of the source kit. For Epics experts who may want
+to use their own versions the *libca* from Epics base, instructions
+for how to do this are given below.
+
+The Python `numpy <https://numpy.org/>`_ module is highly
+recommended. and will be used to automatically convert between EPICS
+waveforms and numpy arrays if available.
+
+The `autosave` module requires the `pyparsing` package, which is widely
+available and often installed by default with many Python distributions.
+The `wx` module requires the `wxPython` package, and the `qt` module
+requires `PyQt` or `PySide`.
Getting Started, Setting up the Epics Environment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Pyepics will find and load the Channel Access dynamic library (*libca.so*,
-*libca.dylib*, or *ca.dll* depending on the system) at runtime in order to
-actually work. For the most commonly used operating systems and
-architectures, modern version of these libraries are provided, and will be
-installed and used with pyepics. We strongly recommend using these.
+Pyepics will find and load the Channel Access dynamic library
+(*libca.so*, *libca.dylib*, or *ca.dll* depending on the system) at
+runtime to do Channel Access communication. As said above, for the
+most commonly used operating systems and architectures, modern version
+of these libraries are provided, and will be installed and used with
+pyepics by default. We recommend using these.
-If these provided versions of *libca* do not work for you, please let us know.
-If you need to or wish to use a different version of *libca*, you can set the
-environmental variable ``PYEPICS_LIBCA`` to the full path of the dynamic
-library to use as *libca*, for example::
+If these provided versions of *libca* do not work for you, please let
+us know. If you need to or wish to use a different version of
+*libca*, you can set the environmental variable ``PYEPICS_LIBCA`` to
+the full path of the dynamic library to use as *libca*, for example::
> export PYEPICS_LIBCA=/usr/local/epics/base-7.0.4/lib/linux-x86_64/libca.so
-Note that *libca* will need to find another Epics CA library *libCom*. This
-is almost always in the same folder as *libca*, but you may need to make sure
-that the *libca* you are pointing to can find the required *libCom*. To
-find out which CA library will be used by pyepics, use:
+Note that *libca* will need to find the library *libCom*, also created
+with Epics Base. This is almost always in the same folder as *libca*
+and can be found without trouble, but you may need to make sure that
+the *libca* you are pointing to can find the required *libCom*.
+
+To find out which CA library will be used by pyepics, use:
>>> import epics
>>> epics.ca.find_libca()
which will print out the full path of the CA dynamic library that will be used.
-With the Epics CA library loaded, you will need to be able to connect to Epics
-Process Variables. Generally, these variables are provided by Epics I/O
-controllers (IOCs) that are processes running on some device on the network.
-If you are connecting to PVs provided by IOCs on your local subnet, you should
-have no trouble. If trying to reach IOCs outside of your immediate subnet, you
-may need to set the environmental variable ``EPICS_CA_ADDR_LIST`` to specify
-which networks to search for PVs.
+With the Epics CA library loaded, you will also need to be able to
+connect to Epics Process Variables. Generally, these variables are
+provided by Epics I/O controllers (IOCs) that are processes running on
+some device on the network. If you are connecting to PVs provided by
+IOCs on your local subnet, you should have no trouble. If you are
+trying to reach IOCs outside of your immediate subnet, you may need to
+set the environmental variable ``EPICS_CA_ADDR_LIST`` to specify which
+networks to search for PVs. Consult your local Epics expert if you
+are having trouble connecting to PVs that you think should be reachable.
Testing
~~~~~~~~~~~~~
-Automated testing of PyEpics is done with the Github actions, for Python 3.8,
-3.9, 3.10, 3.11, and 3.12. This uses an ubuntu-linux environment.
+Automated testing of PyEpics is done with the Github actions, for
+Python 3.10 through 3.14, using an ubuntu-linux environment.
-To run these tests yourself, you will need the `pytest` python module. You
-will also need to run an Epics softIOC as a separate process, and a
-simulator that updates PV values as a separate process. These can all run
-on the same machine or different machines on your network as long as all
-processes can see all the PVs (all using a prefix of `PyTest:`). The
-softIoc cannot be run in a separate terminal process or using the
-`procServ` program. To setup the testing environment, first start the
-testing softIoc in one shell, with::
+To run these tests yourself, you will need the `pytest` python
+module. You will also need to run an Epics softIOC as a separate
+process, and a simulator that updates PV values as a separate process.
+These can all run on the same machine or different machines on your
+network as long as all processes can see all the PVs (all using a
+prefix of `PyTest:`). The softIoc cannot be run in a separate
+terminal process or using the `procServ` program. To setup the
+testing environment, first start the testing softIoc in one shell,
+with::
~> cd tests/Setup
~> softIoc ./st.cmd
@@ -144,7 +151,7 @@ The automated testing process also uses the `coverage` tool to help
identify which parts of the code is actually run by the tests.
Unfortunately, the code for using GUI are not easily tested by the
automated procedures. In addition, a softIoc would need to support all of
-the subclasses of Device, which cannot be gauranteed.
+the subclasses of Device, which cannot be guaranteed.
Development Version
~~~~~~~~~~~~~~~~~~~~~~~~
@@ -161,21 +168,24 @@ Getting Help
For questions, bug reports, feature request, please consider using the
following methods:
- 1. Send email to the Epics Tech Talk mailing list. You can send mail
- directly to Matt Newville <newville@cars.uchicago.ed>, but the mailing
- list has many Epics experts reading it, so someone else interested or
+ 1. Send email to the Epics Tech Talk mailing list. You can send
+ mail directly to the lead author, Matt Newville
+ <newville@cars.uchicago.ed>. The Epics Tech Talk mailing list
+ has many Epics experts reading it, so someone else interested or
knowledgeable about the topic might provide an answer. Since the
- mailing list is archived and the main mailing list for Epics work, a
- question to the mailing list has a better chance of helping someone
- else.
-
- 2. Create an Issue on https://github.com/pyepics/pyepics. Though the
- github Issues seem to be intended for bug tracking, they are a fine
- way to catalog various kinds of questions and feature requests.
-
- 3. If you are sure you have found a bug in existing code, or have
- some code you think would be useful to add to pyepics, consider
- making a Pull Request on https://github.com/pyepics/pyepics.
+ mailing list is archived and the main mailing list for Epics
+ work, a question to the mailing list has a better chance of
+ helping someone else.
+
+ 2. Create an Issue or Discussion on
+ https://github.com/pyepics/pyepics. Github Issues are usually
+ intended for bug tracking, but the traffic for bug reports and
+ discussions about PyEpics is generally very low, so using either
+ is fine.
+
+ 3. If you think you have found a bug in existing code, or have some
+ code you think would be useful to add to pyepics, consider making
+ a Pull Request on https://github.com/pyepics/pyepics.
License
diff --git a/doc/overview.rst b/doc/overview.rst
index 27b1088..0986163 100644
--- a/doc/overview.rst
+++ b/doc/overview.rst
@@ -41,19 +41,19 @@ the remote channel. For larger applications where you find yourself
working with sets of related PVs, you may find the :class:`Device` class
helpful.
-The lowest-level CA functionality is exposed in the :mod:`ca` module, and
-companion :mod:`dbr` module. While not necessary recommended for most use
-cases, this module does provide a fairly complete wrapping of the basic
-EPICS CA library. For people who have used CA from C or other languages,
-this module should be familiar and seem quite usable, if a little more
-verbose and C-like than using PV objects.
+The lowest-level CA functionality is exposed in the :mod:`ca` module,
+and companion :mod:`dbr` module. While the :class:`PV` module is
+recommended for most use cases, :mod:`ca` module does provide a fairly
+complete wrapping of the basic EPICS CA library. For people who have
+used CA from C or other languages this module should be familiar, if a
+little more verbose and C-like than using PV objects.
In addition, the `epics` package contains more specialized modules for
alarms, Epics motors, and several other *devices* (collections of PVs), and
a set of wxPython widget classes for using EPICS PVs with wxPython.
The `epics` package is supported and well-tested on Linux, Mac OS X, and
-Windows with Python versions 2.7, and 3.5 and above.
+Windows with Python versions 3.10 and above.
Quick Start
@@ -110,8 +110,7 @@ function:
PV is internally monitored, with 0 user-defined callbacks:
=============================
-The simplicity and clarity of these functions make them ideal for many
-uses.
+These functions are very simple to use, making them ideal for many uses.
Creating and Using PV Objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -459,5 +458,4 @@ The PyEpics package is actively maintained, but the core library is
reasonably stable and ready to use in production code. Features are being
added slowly, and testing is integrated into development so that the chance
of introducing bugs into existing codes is minimized. The package is
-targeted and tested to work on all supported versions of Python, currently
-Python 3.9 and higher.
+targeted and tested to work on all supported versions of Python.
diff --git a/doc/wx.rst b/doc/wx.rst
index 12c5273..1451448 100644
--- a/doc/wx.rst
+++ b/doc/wx.rst
@@ -238,7 +238,7 @@ PVEnumComboBox
.. class:: PVEnumComboBox(parent, pv=None, **kw)
- A ComboBox linked to an "enum" type PV (such as bi,bo,mbbi,mbbo.) The ComboBox
+ A ComboBox linked to an "enum" type PV (such as bi, bo, mbbi, mbbo.) The ComboBox
is automatically populated with a non-editable list of the PV enum values, allowing
the user to select them from the dropdown.
diff --git a/epics/__init__.py b/epics/__init__.py
index 9bb25f4..6df4bef 100644
--- a/epics/__init__.py
+++ b/epics/__init__.py
@@ -1,5 +1,5 @@
import time
-from . import ca, dbr, pv, alarm, autosave, device, motor, multiproc
+from . import ca, dbr, pv, alarm, device, motor, multiproc
from .version import __version__
__doc__ = f"""
diff --git a/epics/alarm.py b/epics/alarm.py
index 0e9e7da..eecff30 100644
--- a/epics/alarm.py
+++ b/epics/alarm.py
@@ -131,7 +131,8 @@ class Alarm:
"""checks alarm status, act if needed.
"""
if (pvname is None or value is None or
- self.cmp is None or self.trip_point is None): return
+ self.cmp is None or self.trip_point is None):
+ return
val = value
if char_value is None:
diff --git a/epics/ca.py b/epics/ca.py
index 0f66a0a..1ceeaa6 100755
--- a/epics/ca.py
+++ b/epics/ca.py
@@ -1629,7 +1629,7 @@ def get_complete_with_metadata(chid, ftype=None, count=None, timeout=None,
full_value, = get_result
- # print("Get Complete> Unpack ", ncache['value'], count, ftype)
+ # print(f"Get Complete> Unpack {count=}, {ftype}", _cache['value'])
if isinstance(full_value, Exception):
get_failure_reason = full_value
@@ -1641,8 +1641,8 @@ def get_complete_with_metadata(chid, ftype=None, count=None, timeout=None,
metadata = _unpack_metadata(ftype=ftype, dbr_value=extended_data)
val = _unpack(chid, full_value, count=count,
ftype=ftype, as_numpy=as_numpy)
- # print("Get Complete unpacked to ", val)
+ # print(f"Get Complete {as_string=}, {count=}, {ftype=}")
if as_string:
val = _as_string(val, chid, count, ftype)
elif isinstance(val, ctypes.Array) and HAS_NUMPY and as_numpy:
@@ -1703,7 +1703,12 @@ def _as_string(val, chid, count, ftype):
try:
if (ftype in (dbr.CHAR, dbr.TIME_CHAR, dbr.CTRL_CHAR) and
count < AUTOMONITOR_MAXLENGTH):
- val = strjoin('', [chr(i) for i in val if i>0]).strip()
+ bdat = []
+ for i in val:
+ if i == 0:
+ break
+ bdat.append(chr(i))
+ val = strjoin('', bdat).strip()
elif ftype == dbr.ENUM and count == 1:
val = get_enum_strings(chid)[val]
elif count > 1:
diff --git a/epics/dbr.py b/epics/dbr.py
index 4a54b3f..26560d0 100644
--- a/epics/dbr.py
+++ b/epics/dbr.py
@@ -291,7 +291,8 @@ def Name(ftype, reverse=False):
name = ftype.upper()
if name in list(m.values()):
for key, val in m.items():
- if name == val: return key
+ if name == val:
+ return key
return m.get(ftype, 'unknown')
def cast_args(args):
diff --git a/epics/device.py b/epics/device.py
index 37c5ada..64e2c47 100644
--- a/epics/device.py
+++ b/epics/device.py
@@ -242,7 +242,6 @@ class Device:
key, strval = line[:-1].split(' ', 1)
if key in self._pvs:
dtype = self._pvs[key].type
- count = self._pvs[key].count
val = strval
if dtype in ('double', 'float'):
val = float(val)
diff --git a/epics/devices/ad_mca.py b/epics/devices/ad_mca.py
index 8391ad1..9517bbf 100644
--- a/epics/devices/ad_mca.py
+++ b/epics/devices/ad_mca.py
@@ -1,7 +1,6 @@
import numpy as np
-import time
-from epics import PV, caget, caput, poll, Device, get_pv
+from epics import PV, caput, poll, Device, get_pv
MAX_CHAN = 4096
MAX_ROIS = 48
diff --git a/epics/devices/ad_perkinelmer.py b/epics/devices/ad_perkinelmer.py
index a5780a8..7712409 100644
--- a/epics/devices/ad_perkinelmer.py
+++ b/epics/devices/ad_perkinelmer.py
@@ -1,5 +1,4 @@
#!/usr/bin/python
-import sys
import time
from .. import Device
diff --git a/epics/devices/mca.py b/epics/devices/mca.py
index 42a5a10..4be7fa5 100644
--- a/epics/devices/mca.py
+++ b/epics/devices/mca.py
@@ -1,5 +1,4 @@
#!/usr/bin/python
-import sys
import time
import numpy as np
from configparser import ConfigParser
@@ -68,7 +67,7 @@ class ROI(Device):
with_poll=False)
if data_pv is None:
data_pv = self.address
- if isinstance(data_pv, basestring):
+ if isinstance(data_pv, str):
data_pv = get_pv(data_pv)
self._pvs['_dat_'] = data_pv
self._pvs['_net_'] = get_pv(self.address + 'N')
diff --git a/epics/devices/struck.py b/epics/devices/struck.py
index d59fedc..2a8e534 100755
--- a/epics/devices/struck.py
+++ b/epics/devices/struck.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python
import sys
import time
-import copy
import numpy
from .. import Device
from .scaler import Scaler
diff --git a/epics/devices/xspress3.py b/epics/devices/xspress3.py
index b274efc..51bce29 100755
--- a/epics/devices/xspress3.py
+++ b/epics/devices/xspress3.py
@@ -1,12 +1,11 @@
#!/usr/bin/python
-import sys
import os
import time
from configparser import ConfigParser
from epics import Device, caget, caput, poll
from epics.devices.mca import MCA, ROI
-from epics.devices.ad_mca import ADMCA, ADMCAROI
+from epics.devices.ad_mca import ADMCA
MAX_ROIS = 32
diff --git a/epics/wx/motordetailframe.py b/epics/wx/motordetailframe.py
index 2e07a7f..4d36e08 100755
--- a/epics/wx/motordetailframe.py
+++ b/epics/wx/motordetailframe.py
@@ -2,7 +2,6 @@
wxFrame for Detailed Motor Settings, ala medm More (+Setup) screen
"""
-import time
import wx
from wx.lib.scrolledpanel import ScrolledPanel
@@ -70,7 +69,7 @@ class MotorDetailFrame(wx.Frame):
"Copy Motor Template to Clipboard")
menuBar = wx.MenuBar()
- menuBar.Append(fmenu, "&File");
+ menuBar.Append(fmenu, "&File")
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self._onSaveTemplate, id=id_save)
diff --git a/epics/wx/motorpanel.py b/epics/wx/motorpanel.py
index 39ee2b5..f4ce230 100755
--- a/epics/wx/motorpanel.py
+++ b/epics/wx/motorpanel.py
@@ -13,7 +13,7 @@ provides two classes:
import wx
import epics
-from epics.wx.wxlib import PVText, PVFloatCtrl, PVButton, PVComboBox, \
+from epics.wx.wxlib import PVText, PVFloatCtrl, PVButton, \
DelayedEpicsCallback, EpicsFunction
from epics.wx.motordetailframe import MotorDetailFrame
diff --git a/epics/wx/wxlib.py b/epics/wx/wxlib.py
index c5f606d..599d443 100644
--- a/epics/wx/wxlib.py
+++ b/epics/wx/wxlib.py
@@ -1,16 +1,12 @@
"""
wx utility functions for Epics and wxPython interaction
"""
-import wx
-
-import time
import sys
import epics
+
+import wx
import wx.lib.buttons as buttons
import wx.lib.agw.floatspin as floatspin
-
-PyDeadObjectError = Exception
-
from .wxutils import Closure, FloatCtrl, set_float
def EpicsFunction(f):
@@ -24,7 +20,7 @@ def EpicsFunction(f):
"callafter wrapper"
try:
wx.CallAfter(f, *args, **kwargs)
- except PyDeadObjectError:
+ except Exception:
pass
return wrapper
@@ -40,7 +36,7 @@ def DelayedEpicsCallback(fcn):
"default callback"
try:
fcn(*args, **kw)
- except PyDeadObjectError:
+ except Exception:
cb_index, pv = kw.get('cb_info', (None, None))
if hasattr(pv, 'remove_callback'):
try:
@@ -448,7 +444,7 @@ class PVCtrlMixin(PVMixin):
self._SetValue(self._translations.get(raw_value, raw_value))
except TypeError:
pass
- except PyDeadObjectError:
+ except Exception:
pass
@@ -774,7 +770,7 @@ class PVFloatCtrl(FloatCtrl, PVCtrlMixin):
if self.pv.type in ('string', 'char'):
try:
- x = float(self.pv.value)
+ _ = float(self.pv.value)
except:
self._warn('pvFloatCtrl needs a double or float PV')
@@ -903,8 +899,8 @@ class PVFloatSpin(floatspin.FloatSpin, PVCtrlMixin):
both reads and writes the PV on changes.
"""
- def __init__(self, parent, pv=None, deadTime=2500,
- min_val=None, max_val=None, increment=1.0, digits=-1, **kw):
+ def __init__(self, parent, pv=None, deadTime=250,
+ min_val=None, max_val=None, increment=1.0, digits=4, **kw):
"""
Most arguments are common with FloatSpin.
@@ -918,16 +914,17 @@ class PVFloatSpin(floatspin.FloatSpin, PVCtrlMixin):
min_val=min_val, max_val=max_val,
digits=digits, **kw)
PVCtrlMixin.__init__(self, pv=pv, font="", fg=None, bg=None)
- floatspin.EVT_FLOATSPIN(parent, self.GetId(), self.OnSpin)
+ self.Bind(floatspin.EVT_FLOATSPIN, self.OnSpin)
self.deadTimer = wx.Timer(self)
self.deadTime = deadTime
- wx.EVT_TIMER(self, self.deadTimer.GetId(), self.OnTimeout)
+ self.Bind(wx.EVT_TIMER, self.OnTimeout)
@EpicsFunction
def _SetValue(self, value):
"set value"
- floatspin.FloatSpin.SetValue(self, float(self.pv.get()))
+ self.SetValue(float(self.pv.get()))
+ self.SetDigits(self.pv.precision)
@EpicsFunction
def OnSpin(self, event=None):
@@ -1039,6 +1036,7 @@ class PVButton(wx.Button, PVCtrlMixin):
enableValue = False
if self.pv is not None and (self.pv.get() == self.pushValue):
enableValue = False
+ wx.Button.Enable(self, enableValue)
@DelayedEpicsCallback
def _disableEvent(self, **kw):
@@ -1280,7 +1278,7 @@ class PVCollapsiblePane(wx.CollapsiblePane, PVCtrlMixin):
epics.MAJOR_ALARM : major_alarm,
epics.INVALID_ALARM : invalid_alarm }
if self.pv:
- _SetValue(self.pv.value)
+ self._SetValue(self.pv.value)
def _SetValue(self, value):
if value:
diff --git a/epics/wx/wxutils.py b/epics/wx/wxutils.py
index 269f189..9ce5310 100755
--- a/epics/wx/wxutils.py
+++ b/epics/wx/wxutils.py
@@ -63,17 +63,17 @@ def set_float(val):
""" utility to set a floating value,
useful for converting from strings """
out = None
- if not val in (None, ''):
+ if val not in (None, ''):
try:
out = float(val)
except ValueError:
return None
if HAS_NUMPY:
if numpy.isnan(out):
- out = default
+ out = 0
else:
if not(out > 0) and not(out<0) and not(out==0):
- out = default
+ out = 0
return out
def pack(window, sizer):
@@ -117,7 +117,7 @@ def fix_filename(fname):
fix string to be a 'good' filename. This may be a more
restrictive than the OS, but avoids nasty cases.
"""
- out = str(s).translate(TRANS_FILE)
+ out = str(fname).translate(TRANS_FILE)
if out[0] in '-,;[]{}()~`@#':
out = '_%s' % out
return out
diff --git a/pyproject.toml b/pyproject.toml
index bafa258..5cce337 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,7 +21,7 @@ addopts = "--cov=epics --cov-append --cov-report html"
name = "pyepics"
dynamic = ["version"]
# provides = ["epics"]
-requires-python = ">=3.9"
+requires-python = ">=3.10"
description = "Epics Channel Access for Python"
readme = "README.rst"
authors = [{name="Matthew Newville", email="newville@cars.uchicago.edu"}]
@@ -33,15 +33,15 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
"Programming Language :: Python :: Implementation :: CPython",
]
keywords = ["epics"]
-dependencies = ["numpy>=1.23", "pyparsing"]
+dependencies = ["numpy>=1.26", "pyparsing"]
[project.urls]
Homepage = "https://github.com/pyepics/pyepics/"
diff --git a/scripts/mpanel.py b/scripts/mpanel.py
index d24b12b..47d48ce 100644
--- a/scripts/mpanel.py
+++ b/scripts/mpanel.py
@@ -11,10 +11,7 @@ provides two classes:
# Aug 21 2004 M Newville: initial working version.
#
import wx
-try:
- from wx._core import PyDeadObjectError
-except:
- PyDeadObjectError = Exception
+PyDeadObjectError = Exception
import epics
from epics.wx.wxlib import PVText, PVFloatCtrl, PVButton, PVComboBox, \
@@ -22,7 +19,7 @@ from epics.wx.wxlib import PVText, PVFloatCtrl, PVButton, PVComboBox, \
from epics.wx.motordetailframe import MotorDetailFrame
-from epics.wx.utils import LCEN, RCEN, CEN, LTEXT, RIGHT, pack, add_button
+from wxutils import LCEN, RCEN, CEN, LTEXT, RIGHT, pack, add_button
from larch.utils import debugtime
diff --git a/scripts/wxfloat_probe.py b/scripts/wxfloat_probe.py
new file mode 100755
index 0000000..7ecb5a4
--- /dev/null
+++ b/scripts/wxfloat_probe.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+#
+# simple PV Probe application for Float PVs
+
+import wx
+import sys
+import epics
+from epics.wx import PVText, PVFloatCtrl, PVFloatSpin
+
+class ProbeFrame(wx.Frame):
+ def __init__(self, parent=None, **kwds):
+
+ wx.Frame.__init__(self, parent, wx.ID_ANY, '',
+ wx.DefaultPosition, size=(400, 400), **kwds)
+ self.SetTitle("Connect to Float PV:")
+
+ self.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.BOLD,False))
+
+ sizer = wx.GridBagSizer(3, 3)
+ panel = wx.Panel(self)
+
+ self.pvname = wx.TextCtrl(panel, value='', size=(150, -1),
+ style=wx.TE_PROCESS_ENTER)
+ self.pvname.Bind(wx.EVT_CHAR, self.onPVName)
+
+ self.pvtext = PVText(panel, None, size=(100, -1))
+ self.pvfloat = PVFloatCtrl(panel, None, size=(100, -1))
+ self.pvfspin = PVFloatSpin(panel, None, size=(100, -1))
+
+ pvname_label = wx.StaticText(panel, label='PV Name:', size=(150, -1))
+ pvval_label = wx.StaticText(panel, label='PVText:', size=(150, -1))
+ pvfloat_label = wx.StaticText(panel, label='PVFloatControl:', size=(150, -1))
+ pvfspin_label = wx.StaticText(panel, label='PVFloatSpin:', size=(150, -1))
+
+ sizer.Add(pvname_label, (0, 0), (1, 1), wx.ALIGN_LEFT, 1)
+ sizer.Add(self.pvname, (0, 1), (1, 1), wx.ALIGN_LEFT, 1)
+ sizer.Add(pvval_label, (1, 0), (1, 1), wx.ALIGN_LEFT, 1)
+ sizer.Add(self.pvtext, (1, 1), (1, 1), wx.ALIGN_LEFT, 1)
+ sizer.Add(pvfloat_label, (2, 0), (1, 1), wx.ALIGN_LEFT, 1)
+ sizer.Add(self.pvfloat, (2, 1), (1, 1), wx.ALIGN_LEFT, 1)
+ sizer.Add(pvfspin_label, (3, 0), (1, 1), wx.ALIGN_LEFT, 1)
+ sizer.Add(self.pvfspin, (3, 1), (1, 1), wx.ALIGN_LEFT, 1)
+
+ panel.SetSizer(sizer)
+ sizer.Fit(panel)
+
+ s = wx.BoxSizer(wx.VERTICAL)
+ s.Add(panel)
+ s.Fit(self)
+
+ self.SetSize((400, 150))
+ self.Refresh()
+
+ def onPVName(self, event=None):
+ if event.GetKeyCode() == wx.WXK_RETURN:
+ pvname = self.pvname.GetValue().strip()
+ if len(pvname) > 1:
+ self.pvtext.SetPV(pvname)
+ self.pvfloat.SetPV(pvname)
+ self.pvfspin.SetPV(pvname)
+ event.Skip()
+
+if __name__ == '__main__':
+ app = wx.App(redirect=False)
+ ProbeFrame().Show()
+ app.MainLoop()