Skip to content

Commit

Permalink
Added an example for the pydm archiver time plot widget. Also added a…
Browse files Browse the repository at this point in the history
… live data flag to the receiveNewValue method, so that the widget can be used to fetch live and archived or just archived data
  • Loading branch information
YektaY committed Feb 21, 2024
1 parent ac354b7 commit f712d13
Show file tree
Hide file tree
Showing 306 changed files with 14,290 additions and 6,732 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: pre-commit

on:
pull_request:
push:
branches: [main]

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- uses: pre-commit/action@v3.0.0
20 changes: 6 additions & 14 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This workflow will install pydm dependencies, lint with flake8, and run the test suite, for all combinations
# This workflow will install pydm dependencies and run the test suite for all combinations
# of operating systems and version numbers specified in the matrix

name: Build Status
Expand All @@ -20,8 +20,8 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: [3.7, 3.8, 3.9]
pyqt-version: [5.12.3, 5.15.7]
python-version: ['3.8', '3.9', '3.10']
pyqt-version: [5.12.3, 5.15.9]
env:
DISPLAY: ':99.0'
QT_MAC_WANTS_LAYER: 1 # PyQT gui tests involving qtbot interaction on macOS will fail without this
Expand All @@ -38,30 +38,22 @@ jobs:
- name: Install python packages
shell: bash -el {0}
run: |
# Note the pinning of zipp here is because versions 3.16.0+ do not support python 3.7. Specifying zipp can be entirely removed (will be pulled in by flake8) if pydm drops support for 3.7
if [ "$RUNNER_OS" == "Windows" ]; then
mamba install flake8 zipp=3.15.0 pyqt=${{ matrix.pyqt-version }}
mamba install pyqt=${{ matrix.pyqt-version }}
mamba install --file requirements.txt --file windows-dev-requirements.txt
else
mamba install flake8 zipp=3.15.0 pyqt=${{ matrix.pyqt-version }} $(cat requirements.txt dev-requirements.txt)
mamba install pyqt=${{ matrix.pyqt-version }} $(cat requirements.txt dev-requirements.txt)
fi
- name: Install packages for testing a pyqt app on linux
shell: bash -el {0}
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
sudo apt install xvfb herbstluftwm libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils
sudo apt install xvfb herbstluftwm libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils
sudo /sbin/start-stop-daemon --start --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset
sleep 3
sudo /sbin/start-stop-daemon --start --pidfile /tmp/custom_herbstluftwm_99.pid --make-pidfile --background --exec /usr/bin/herbstluftwm
sleep 1
fi
- name: Lint with flake8
shell: bash -el {0}
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings.
flake8 . --count --exit-zero --max-line-length=120 --statistics
- name: Test with pytest
shell: bash -el {0}
run: |
Expand Down
18 changes: 18 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: end-of-file-fixer
files: '\.(py|txt)$' # Only run on .py and .txt files
- id: trailing-whitespace
files: '\.(py|txt)$' # Only run on .py and .txt files
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
args: [--line-length, '120']
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.287
hooks:
- id: ruff
args: [--line-length, '120', --fix, --exit-non-zero-on-fix]
71 changes: 27 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
[![Build Status](https://github.com/slaclab/pydm/actions/workflows/run-tests.yml/badge.svg?branch=master)](https://github.com/slaclab/pydm/actions/workflows/run-tests.yml)

![PyDM: Python Display Manager](pydm_banner_full.png)

<p>
<img src="pydm_launcher/icons/pydm_128.png" width="128" height="128" align="right"/>
<h1>PyDM: Python Display Manager</h1>
</p>

<p align="left">
PyDM is a PyQt-based framework for building user interfaces for control systems.
The goal is to provide a no-code, drag-and-drop system to make simple screens,
as well as a straightforward Python framework to build complex applications.
<br>
<br>
</p>
<p align="center">
<h1 align="center">PyDM: Python Display Manager</h1>

<p align="center">
PyDM is a PyQt-based framework for building user interfaces for control systems.
The goal is to provide a no-code, drag-and-drop system to make simple screens,
as well as a straightforward Python framework to build complex applications.
<br>
<br>
<strong>« Explore PyDM <a href="https://slaclab.github.io/pydm/">docs</a> and <a href="https://slaclab.github.io/pydm-tutorial">tutorials</a> »</strong>
<br>
<br>
<a href="https://github.com/slaclab/pydm/issues/new?template=bug-report.md">Report bug</a>
·
<a href="https://github.com/slaclab/pydm/issues/new?template=feature-request.md&labels=request">Request feature</a>
·
<a href="https://github.com/slaclab/pydm/blob/master/.github/CONTRIBUTING.md">How to Contribute</a>
·
<a href="https://github.com/slaclab/pydm/blob/master/.github/SUPPORT.md">Support</a>
</p>
<strong>« Explore PyDM <a href="https://slaclab.github.io/pydm/">docs</a> and <a href="https://slaclab.github.io/pydm/tutorials/index.html">tutorials</a> »</strong>
<br>
<br>
<a href="https://github.com/slaclab/pydm/issues/new?template=bug-report.md">Report bug</a>
·
<a href="https://github.com/slaclab/pydm/issues/new?template=feature-request.md&labels=request">Request feature</a>
·
<a href="https://github.com/slaclab/pydm/blob/master/.github/CONTRIBUTING.md">How to Contribute</a>
·
<a href="https://github.com/slaclab/pydm/blob/master/.github/SUPPORT.md">Support</a>
</p>

<br>
Expand Down Expand Up @@ -71,7 +76,7 @@ python scripts/pydm examples/home.ui
```

# Building the Documentation Locally
In order to build the documentation you will need to instll some dependencies
In order to build the documentation you will need to install some dependencies
that are not part of the runtime dependencies of PyDM.

Assuming that you have cloned this repository do:
Expand Down Expand Up @@ -111,27 +116,5 @@ pip install .[all]
When using Anaconda to install PyDM at a Linux Environment it will automatically
define the PYQTDESIGNERPATH environment variable pointing to /etc/pydm which
will have a file named designer_plugin.py which will make all the PyDM widgets
available to the Qt Designer.

### Most Recent Development Build

[![Anaconda-Server Badge](https://anaconda.org/pydm-dev/pydm/badges/installer/conda.svg)](https://conda.anaconda.org/pydm-dev)
[![Anaconda-Server Badge](https://anaconda.org/pydm-dev/pydm/badges/platforms.svg)](https://anaconda.org/pydm-dev/pydm)
[![Anaconda-Server Badge](https://anaconda.org/pydm-dev/pydm/badges/version.svg)](https://anaconda.org/pydm-dev/pydm)
[![Anaconda-Server Badge](https://anaconda.org/pydm-dev/pydm/badges/downloads.svg)](https://anaconda.org/pydm-dev/pydm)


```sh
conda install -c pydm-dev -c conda-forge pydm
```
### Most Recent Tagged Build

[![Anaconda-Server Badge](https://anaconda.org/pydm-tag/pydm/badges/installer/conda.svg)](https://conda.anaconda.org/pydm-tag)
[![Anaconda-Server Badge](https://anaconda.org/pydm-tag/pydm/badges/platforms.svg)](https://anaconda.org/pydm-tag/pydm)
[![Anaconda-Server Badge](https://anaconda.org/pydm-tag/pydm/badges/version.svg)](https://anaconda.org/pydm-tag/pydm)
[![Anaconda-Server Badge](https://anaconda.org/pydm-tag/pydm/badges/downloads.svg)](https://anaconda.org/pydm-tag/pydm)


```sh
conda install -c pydm-tag -c conda-forge pydm
```
available to the Qt Designer. For more information please see
our <a href="https://slaclab.github.io/pydm/installation.html">installation guide</a>.
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pytest-cov
pytest-timeout
p4p
pyca
pre-commit
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
146 changes: 146 additions & 0 deletions docs/source/_static/tutorials/code/all_motors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import os
import json
from pydm import Display
from qtpy.QtWidgets import (
QVBoxLayout,
QHBoxLayout,
QGroupBox,
QLabel,
QLineEdit,
QPushButton,
QScrollArea,
QFrame,
QApplication,
QWidget,
)
from qtpy import QtCore
from pydm.widgets import PyDMEmbeddedDisplay


class AllMotorsDisplay(Display):
def __init__(self, parent=None, args=[], macros=None):
super(AllMotorsDisplay, self).__init__(parent=parent, args=args, macros=None)
# Placeholder for data to filter
self.data = []
# Reference to the PyDMApplication
self.app = QApplication.instance()
# Assemble the Widgets
self.setup_ui()
# Load data from file
self.load_data()

def minimumSizeHint(self):
# This is the default recommended size
# for this screen
return QtCore.QSize(750, 120)

def ui_filepath(self):
# No UI file is being used
return None

def setup_ui(self):
# Create the main layout
main_layout = QVBoxLayout()
self.setLayout(main_layout)

# Create a Label to be the title
lbl_title = QLabel("Motors Diagnostic")
# Add some StyleSheet to it
lbl_title.setStyleSheet(
"\
QLabel {\
qproperty-alignment: AlignCenter;\
border: 1px solid #FF17365D;\
border-top-left-radius: 15px;\
border-top-right-radius: 15px;\
background-color: #FF17365D;\
padding: 5px 0px;\
color: rgb(255, 255, 255);\
max-height: 25px;\
font-size: 14px;\
}"
)

# Add the title label to the main layout
main_layout.addWidget(lbl_title)

# Create the Search Panel layout
search_layout = QHBoxLayout()

# Create a GroupBox with "Filtering" as Title
gb_search = QGroupBox(parent=self)
gb_search.setTitle("Filtering")
gb_search.setLayout(search_layout)

# Create a label, line edit and button for filtering
lbl_search = QLabel(text="Filter: ")
self.txt_filter = QLineEdit()
self.txt_filter.returnPressed.connect(self.do_search)
btn_search = QPushButton()
btn_search.setText("Search")
btn_search.clicked.connect(self.do_search)

# Add the created widgets to the layout
search_layout.addWidget(lbl_search)
search_layout.addWidget(self.txt_filter)
search_layout.addWidget(btn_search)

# Add the Groupbox to the main layout
main_layout.addWidget(gb_search)

# Create the Results Layout
self.results_layout = QVBoxLayout()
self.results_layout.setContentsMargins(0, 0, 0, 0)

# Create a Frame to host the results of search
self.frm_result = QFrame(parent=self)
self.frm_result.setLayout(self.results_layout)

# Create a ScrollArea so we can properly handle
# many entries
scroll_area = QScrollArea(parent=self)
scroll_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
scroll_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
scroll_area.setWidgetResizable(True)

# Add the Frame to the scroll area
scroll_area.setWidget(self.frm_result)

# Add the scroll area to the main layout
main_layout.addWidget(scroll_area)

def load_data(self):
# Extract the directory of this file...
base_dir = os.path.dirname(os.path.realpath(__file__))
# Concatenate the directory with the file name...
data_file = os.path.join(base_dir, "motor_db.txt")
# Open the file so we can read the data...
with open(data_file, "r") as f:
# For each line in the file...
for entry in f.readlines():
# Append to the list of data...
self.data.append(entry[:-1])

def do_search(self):
# For each widget inside the results frame, lets destroy them
for widget in self.frm_result.findChildren(QWidget):
widget.setParent(None)
widget.deleteLater()

# Grab the filter text
filter_text = self.txt_filter.text()

# For every entry in the dataset...
for entry in self.data:
# Check if they match our filter
if filter_text.upper() not in entry.upper():
continue
# Create a PyDMEmbeddedDisplay for this entry
disp = PyDMEmbeddedDisplay(parent=self)
disp.macros = json.dumps({"MOTOR": entry})
disp.filename = "inline_motor.ui"
disp.setMinimumWidth(700)
disp.setMinimumHeight(40)
disp.setMaximumHeight(100)
# Add the Embedded Display to the Results Layout
self.results_layout.addWidget(disp)
Loading

0 comments on commit f712d13

Please sign in to comment.