Skip to content
Snippets Groups Projects
Commit f7d757cd authored by Christoph Schmidt's avatar Christoph Schmidt
Browse files

Updated to version 1.0.0

Added new example. Updated README.md
parent 39adaf3e
No related branches found
No related tags found
No related merge requests found
......@@ -8,6 +8,9 @@
<orderEntry type="jdk" jdkName="Python 3.12 (confighandler)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">
<option name="keepMatchingSpecifier" value="false" />
</component>
<component name="PyNamespacePackagesService">
<option name="namespacePackageFolders">
<list>
......
# -*- coding: utf-8 -*-
"""
Author(s): Christoph Schmidt <christoph.schmidt@tugraz.at>
Created: 2023-10-19 12:35
Package Version:
Description:
"""
import sys
sys.path.append("../src")
import confighandler as cfg
class SecondConfig(cfg.ConfigNode):
def __init__(self, enable_log=True) -> None:
# Call the base class (important!)
super().__init__(enable_log=enable_log)
# Some fields
# Create a field of type int. Set a default value, a friendly name and a description
self.test_int: cfg.Field[int] = cfg.Field(1,
friendly_name="My Test Int",
description="This is just an integer")
self.register()
class ApplicationConfig(cfg.ConfigNode):
def __init__(self, enable_log=True) -> None:
# Call the base class (important!)
super().__init__(enable_log=enable_log)
# Some fields
# Create a field of type int. Set a default value, a friendly name and a description
self.counter: cfg.Field[int] = cfg.Field(1,
friendly_name="My Counter",
description="This is just an integer")
self.version: cfg.Field[str] = cfg.Field("v1.0",
friendly_name="Version",
description="The version")
# You can also omit the friendly name and description
self.check: cfg.Field[bool] = cfg.Field(False)
# Some other fields
# Also possible to create a field of type list
self.my_tuple: cfg.Field[tuple] = cfg.Field((1, 2))
self.any_list: cfg.Field[list] = cfg.Field([1, 2])
# Even a nested config is possible
self.second_config: SecondConfig = SecondConfig()
# Don't forget to register the fields (important!)
self.register()
# ConfigHandler
## Description
This module is used to handle configuration files for flexsensor.
It hgas been designed, so the user can create a config with an UI, automatically connected to the signal and slots.
This module is used to handle configuration files for FlexSensor.
It has been designed, so the user can create a config with a UI, automatically connected to the signal and slots.
## Requirements
Install the requirements with pip:
```python
pip install pyside6, rich, pyyaml
```bash
pip install -r requirements.txt
````
or
```bash
pip install PySide6 PyYAML rich
```
## Installing this repo to yout project using pip
Just add the following line to your requirements.txt
```bash
git+https://gitlab.tugraz.at/flexsensor-public/lasercontrol.git@<branch>
# e.g., from branch main
git+https://gitlab.tugraz.at/flexsensor-public/lasercontrol.git@main
```
oder directly using pip (without requirements.txt)
```bash
# or manually
pip install git+https://gitlab.tugraz.at/flexsensor-public/lasercontrol.git@<branch>
```
## Usage
The Usage is straight forward. Just create a new ```ConfigNode``` object and call the show() method.
Example files can be found in `./examples`.
The usage is straight forward. Just create a new ```ConfigNode``` object and call the show() method.
### Creating a config
Before you can start working woith the config, you need to create some kind of sceleton. This
has three advantages:
1. You can define the type of the fields. You can give them friendly names and descriptions.
2. The parsing of the config file is much easier, because the parser knows the type of the fields.
3. When working with this library, you can use the auto completion of your IDE, since it is a class.
```python
import confighandler as cfg
class SecondConfig(cfg.ConfigNode):
class ApplicationConfig(ConfigNode):
def __init__(self, enable_log=True) -> None:
# Call the base class (important!)
super().__init__(enable_log=enable_log)
# Some fields
# Create a field of type int. Set a default value, a friendly name and a description
self.test_int: cfg.Field[int] = cfg.Field(1,
friendly_name="My Test Int",
description="This is just an integer")
#
class ApplicationConfig(cfg.ConfigNode):
def __init__(self) -> None:
def __init__(self, enable_log=True) -> None:
# Call the base class (important!)
super().__init__()
super().__init__(enable_log=enable_log)
# Some fields
self.output_directory: Field[Path] = Field(Path("C:\\{wafer_nr}"))
self.wafer_version: Field[str] = Field("v1.0")
self.wafer_number: Field[int] = Field(1)
# A field with an description
self.wafer_nr: Field[str] = Field("12345ABCD_{wafer_number}",
friendly_name="Wafer Number",
description="The version of the wafer")
# Create a field of type int. Set a default value, a friendly name and a description
self.counter: cfg.Field[int] = cfg.Field(1,
friendly_name="My Counter",
description="This is just an integer")
self.version: cfg.Field[str] = cfg.Field("v1.0",
friendly_name="Version",
description="The version")
# You can also omit the friendly name and description
self.check: cfg.Field[bool] = cfg.Field(False)
# Some other fields
self.my_tuple: Field[tuple] = Field((1,2))
self.any_list: Field[list] = Field([1, 2])
# Also possible to create a field of type list
self.my_tuple: cfg.Field[tuple] = cfg.Field((1,2))
self.any_list: cfg.Field[list] = cfg.Field([1, 2])
# Even a nested config is possible
self.other_config: OtherConfig = OtherConfig()
self.second_config: SecondConfig = SecondConfig()
# Don't forget to register the fields (important!)
self.register()
```
### Loading and saving a config
It is possible to load and save a config. The config is saved as a yaml file.
```python
from ApplicationConfig import ApplicationConfig
if __name__ == "__main__":
config = ApplicationConfig(enable_log=True)
config.save('./configs/ApplicationConfig.yaml')
config.load('./configs/ApplicationConfig.yaml')
```
### Autosaving
It is also possible to autosave a config. This is useful, if you want to save the config, when the user changes a value.
```python
from ApplicationConfig import ApplicationConfig
if __name__ == "__main__":
config = ApplicationConfig(enable_log=True)
config.autosave(enable=True, path='./configs_autosave')
```
### Creating a UI
The condifg handler build an UI in the background. You can access the widget using
```python
import logging
import sys
from PySide6 import QtWidgets
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QTreeWidget
from ApplicationConfig import ApplicationConfig
if __name__ == "__main__":
# Creating the UI
window = QMainWindow()
wdg = QWidget()
grd = QtWidgets.QGridLayout()
wdg.setLayout(grd)
# Add the config to the UI
config = ApplicationConfig(enable_log=True)
conf_view = config.view.widget()
grd.addWidget(conf_view, 0, 0)
window.setCentralWidget(wdg)
window.show()
sys.exit(app.exec())
```
or using a tree view (which is sometimes more useful)
```python
import logging
import sys
from PySide6 import QtWidgets
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QTreeWidget
from ApplicationConfig import ApplicationConfig
if __name__ == "__main__":
# Creating the UI
window = QMainWindow()
wdg = QWidget()
grd = QtWidgets.QGridLayout()
wdg.setLayout(grd)
# Add the config to the UI
config = ApplicationConfig(enable_log=True)
# Create a tree view
tree = QTreeWidget()
tree.setColumnCount(3)
tree.setHeaderLabels(["Name", "Type", "Description"])
# Get the tree item
config_item = config.view.ui_tree_widget_item(tree)
tree.addTopLevelItem(config_item)
grd.addWidget(tree, 2, 0)
window.setCentralWidget(wdg)
window.show()
sys.exit(app.exec())
```
## Troubleshoting
When working insde the exmaples folder, you need to add the confighandler folder to the python path.
```python
import sys
sys.path.append('../src/')
```
......@@ -11,16 +11,10 @@ if __name__ == "__main__":
app = QApplication(sys.argv)
# setup the logging module
FORMAT = "%(message)s"
logging.basicConfig(
level="DEBUG", format=FORMAT, datefmt="[%X]", handlers=[
RichHandler(rich_tracebacks=True)
]
)
config = ApplicationConfig(enable_log=True)
print(config.load('./configs/ApplicationConfig.yaml'))
config.autosave(enable=True, path='./configs_autosave')
#print(config.load('./configs/ApplicationConfig.yaml'))
#config.autosave(enable=True, path='./configs_autosave')
#print(config.wafer_version)
#config.wafer_version.get()
......
[project]
name = "confighandler"
version = "0.0.3"
version = "1.0.0"
authors = [
{ name="Christoph Schmidt", email="cschmidt.fs@gmail.com" },
]
......
PySide6
PyYAML
rich
\ No newline at end of file
import logging
import os
import sys
from rich.logging import RichHandler
FORMAT = "%(message)s"
logging.basicConfig(
level="DEBUG", format=FORMAT, datefmt="[%X]", handlers=[
RichHandler(rich_tracebacks=True)
]
)
sys.path.append(os.path.join(os.path.dirname(__file__), '../'))
from .controller.Field import Field
from .controller.ConfigNode import ConfigNode
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Author(s): Christoph Schmidt <christoph.schmidt@tugraz.at>
Created: 2023-10-19 12:35
Package Version:
Description:
"""
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '../'))
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Author(s): Christoph Schmidt <christoph.schmidt@tugraz.at>
Created: 2023-10-19 12:35
Package Version:
Description:
"""
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '../'))
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment