Skip to content

Commit

Permalink
Release v0.1.0-alpha (#45)
Browse files Browse the repository at this point in the history
This PR is related to #44.
  • Loading branch information
BECATRUE authored Jun 24, 2023
2 parents ef2b53e + a5d8bc7 commit 963bab9
Show file tree
Hide file tree
Showing 15 changed files with 773 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''

---

### Describe the bug
A clear and concise description of what the bug is.

### Expected behavior
A clear and concise description of what you expected to happen.

### To Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

### Expected causes and correction methods
Even if you don't know the exact reason, please write it down.

### Screenshots
If applicable, add screenshots to help explain your problem.

### Additional context
Add any other context about the problem here.
17 changes: 17 additions & 0 deletions .github/ISSUE_TEMPLATE/implement-new-feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: Implement a new feature
about: Create an article about the motivation and specification of a new feature
title: ''
labels: enhancement
assignees: ''

---

### Feature you want to implement
What is the feature you want to implement?

### How the feature is implemented
ex) Add *B* method to *A* class, Upgrade *C* model

### Additional context
Add any other context or screenshots about the feature here.
33 changes: 33 additions & 0 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Pylint

on: [push]

env:
QIWIS_VERSION: v2.0.2

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
sudo apt-get update
python -m pip install --upgrade pip
pip install pylint
- name: Add dependencies about external libraries
run: |
pip install pyqt5
pip install requests
pip install git+https://github.com/snu-quiqcl/qiwis.git@${{ env.QIWIS_VERSION }}
- name: Analyze the code with pylint
run: |
pylint iquip --report=y
pylint tests --rcfile tests/.pylintrc
34 changes: 34 additions & 0 deletions .github/workflows/unittest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Unit test

on: [push]

env:
QIWIS_VERSION: v2.0.2

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
sudo apt-get update
python -m pip install --upgrade pip
pip install coverage
- name: Add dependencies about external libraries
run: |
pip install pyqt5
pip install requests
sudo apt-get install python3-pyqt5
pip install git+https://github.com/snu-quiqcl/qiwis.git@${{ env.QIWIS_VERSION }}
- name: Run the unit tests and check coverage
run: |
xvfb-run `which coverage` run -m unittest discover
xvfb-run `which coverage` report --include="iquip/*.py"
8 changes: 8 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[MASTER]
extension-pkg-whitelist=PyQt5

[BASIC]
argument-rgx=_?_?(?:(?:[a-z0-9]+(?:_[a-z0-9]+)*_?_?)|(?:[a-z0-9]+(?:[A-Z][a-z0-9]*)*))$
attr-rgx=_?_?(?:(?:[a-z0-9]+(?:_[a-z0-9]+)*_?_?)|(?:[a-z0-9]+(?:[A-Z][a-z0-9]*)*))$
method-rgx=_?_?(?:(?:[a-z0-9]+(?:_[a-z0-9]+)*_?_?)|(?:[a-z0-9]+(?:[A-Z][a-z0-9]*)*))$
variable-rgx=_?_?(?:(?:[a-z0-9]+(?:_[a-z0-9]+)*_?_?)|(?:[a-z0-9]+(?:[A-Z][a-z0-9]*)*))$
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# iquip
Ion trap Quantum computing User Interface Project

[![Pylint](https://github.com/snu-quiqcl/iquip/actions/workflows/pylint.yml/badge.svg)](https://github.com/snu-quiqcl/iquip/actions/workflows/pylint.yml)
[![Unit test](https://github.com/snu-quiqcl/iquip/actions/workflows/unittest.yml/badge.svg)](https://github.com/snu-quiqcl/iquip/actions/workflows/unittest.yml)
Empty file added iquip/__init__.py
Empty file.
Empty file added iquip/apps/__init__.py
Empty file.
189 changes: 189 additions & 0 deletions iquip/apps/explorer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
"""App module for showing the experiment list and opening an experiment."""

import posixpath
from typing import Callable, List, Optional, Tuple, Union

import requests
from PyQt5.QtCore import QObject, Qt, QThread, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import (
QPushButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
)

import qiwis

class ExplorerFrame(QWidget):
"""Frame for showing the experiment list and opening an experiment.
Attributes:
fileTree: The tree widget for showing the file structure.
reloadButton: The buttont for reloading the fileTree.
openButton: The button for opening the selected experiment file.
"""

def __init__(self, parent: Optional[QWidget] = None):
"""Extended."""
super().__init__(parent=parent)
# widgets
self.fileTree = QTreeWidget(self)
self.fileTree.header().setVisible(False)
self.reloadButton = QPushButton("Reload", self)
self.openButton = QPushButton("Open", self)
# layout
layout = QVBoxLayout(self)
layout.addWidget(self.reloadButton)
layout.addWidget(self.fileTree)
layout.addWidget(self.openButton)


class _FileFinderThread(QThread):
"""QThread for finding the file list using a command line.
Signals:
fetched(experimentList, widget): The file list is fetched.
Attributes:
path: The path of the directory to search for experiment files.
widget: The widget corresponding to the path.
"""

fetched = pyqtSignal(list, object)

def __init__(
self,
path: str,
widget: Union[QTreeWidget, QTreeWidgetItem],
callback: Callable[[List[str], Union[QTreeWidget, QTreeWidgetItem]], None],
parent: Optional[QObject] = None
):
"""Extended.
Args:
path, widget: See the attributes section in _FileFinderThread.
callback: The callback method called after this thread is finished.
"""
super().__init__(parent=parent)
self.path = path
self.widget = widget
self.fetched.connect(callback, type=Qt.QueuedConnection)

def run(self):
"""Overridden.
Fetches the file list using a command line.
Searches for only files in path, not in deeper path and adds them into the widget.
After finished, the fetched signal is emitted.
"""
try:
response = requests.get("http://127.0.0.1:8000/ls/",
params={"directory": self.path},
timeout=10)
response.raise_for_status()
experimentList = response.json()
except requests.exceptions.RequestException as err:
print(err)
return
self.fetched.emit(experimentList, self.widget)


class ExplorerApp(qiwis.BaseApp):
"""App for showing the experiment list and opening an experiment.
Attributes:
explorerFrame: The frame that shows the file tree.
thread: The _FileFinderThread object.
"""

def __init__(self, name: str, parent: Optional[QObject] = None):
"""Extended."""
super().__init__(name, parent=parent)
self.explorerFrame = ExplorerFrame()
self.loadFileTree()
# connect signals to slots
self.explorerFrame.fileTree.itemExpanded.connect(self.lazyLoadFile)
self.explorerFrame.reloadButton.clicked.connect(self.loadFileTree)
self.explorerFrame.openButton.clicked.connect(self.openExperiment)

@pyqtSlot()
def loadFileTree(self):
"""Loads the experiment file structure in self.explorerFrame.fileTree."""
self.explorerFrame.fileTree.clear()
self.thread = _FileFinderThread(
".",
self.explorerFrame.fileTree,
self._addFile,
self
)
self.thread.start()

@pyqtSlot(QTreeWidgetItem)
def lazyLoadFile(self, experimentFileItem: QTreeWidgetItem):
"""Loads the experiment file in the directory.
This will be called when a directory item is expanded,
so it makes loading files lazy.
Args:
experimentFileItem: The expanded file item.
"""
if experimentFileItem.childCount() != 1 or experimentFileItem.child(0).columnCount() != 0:
return
# Remove the empty item of an unloaded directory.
experimentFileItem.takeChild(0)
experimentPath = self.fullPath(experimentFileItem)
self.thread = _FileFinderThread(
experimentPath,
experimentFileItem,
self._addFile,
self
)
self.thread.start()

def _addFile(self, experimentList: List[str], widget: Union[QTreeWidget, QTreeWidgetItem]):
"""Adds the files into the children of the widget.
A file or directory which starts with "_" will be ignored, e.g. __pycache__/.
Args:
experimentList: The list of files under the widget path.
widget: See _FileFinderThread class.
"""
for experimentFile in experimentList:
if experimentFile.startswith("_"):
continue
if experimentFile.endswith("/"):
experimentFileItem = QTreeWidgetItem(widget)
experimentFileItem.setText(0, experimentFile[:-1])
# Make an empty item for indicating that it is a directory.
QTreeWidgetItem(experimentFileItem)
elif experimentFile.endswith(".py"):
experimentFileItem = QTreeWidgetItem(widget)
experimentFileItem.setText(0, experimentFile)

@pyqtSlot()
def openExperiment(self):
"""Opens the experiment builder of the selected experiment.
Once the openButton is clicked, this is called.
If the selected element is a directory, it will be ignored.
TODO(BECATRUE): Open the experiment builder. It will be implemented in Basic Runner project.
"""
experimentFileItem = self.explorerFrame.fileTree.currentItem()
experimentPath = self.fullPath(experimentFileItem) # pylint: disable=unused-variable

def fullPath(self, experimentFileItem: QTreeWidgetItem) -> str:
"""Finds the full path of the file item and returns it.
Args:
experimentFileItem: The file item to get its full path.
"""
paths = [experimentFileItem.text(0)]
while experimentFileItem.parent():
experimentFileItem = experimentFileItem.parent()
paths.append(experimentFileItem.text(0))
return posixpath.join(*reversed(paths))

def frames(self) -> Tuple[ExplorerFrame]:
"""Overridden."""
return (self.explorerFrame,)
Loading

0 comments on commit 963bab9

Please sign in to comment.