Skip to content

Commit

Permalink
Add better Python indi example
Browse files Browse the repository at this point in the history
  • Loading branch information
joseph-long committed Dec 21, 2023
1 parent 1526698 commit 3cacf3d
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 12 deletions.
12 changes: 12 additions & 0 deletions apps/pythonIndiExample/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
APP=pythonIndiExample
PYTHON_SCRIPTS_PREFIX=$(shell python -c "import sysconfig; print(sysconfig.get_path('scripts'))")

all : install

.PHONY: all install

install:
sudo python -c 'import purepyindi2' || (echo "Need purepyindi2 installed to $(shell which python)" && exit 1)
sudo python -c 'import xconf' || (echo "Need xconf installed to $(shell which python)" && exit 1)
sudo python -m pip install -e .
sudo ln -sfv $(PYTHON_SCRIPTS_PREFIX)/$(APP) /opt/MagAOX/bin/$(APP)
15 changes: 15 additions & 0 deletions apps/pythonIndiExample/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "pythonIndiExample"
description = "Python INDI device implementation example"
version = "2023.12.21"

authors = [
{name = "Joseph D. Long", email = "[email protected]"},
]

[project.scripts]
pythonIndiExample = "pythonIndiExample:PythonIndiExample.console_app"
18 changes: 18 additions & 0 deletions apps/pythonIndiExample/pythonIndiExample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys
import logging
import xconf
from magaox.indi.device import XDevice, BaseConfig

log = logging.getLogger(__name__)

@xconf.config
class ExampleConfig(BaseConfig):
"""Example Python INDI device for MagAO-X
"""
configurable_doodad_1 : str = xconf.field(default="abc", help="Configurable doodad 1")

class PythonIndiExample(XDevice):
config : ExampleConfig

def loop(self):
log.info("Looping")
73 changes: 61 additions & 12 deletions python/magaox/indi/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,65 @@
import psutil
from purepyindi2 import Device, transports
import toml
import typing

log = logging.getLogger(__name__)

import xconf

@xconf.config
class BaseConfig:
sleep_interval_sec : float = xconf.field(default=1.0, help="Main loop logic will be run every `sleep_interval_sec` seconds")

@classmethod
def from_config(
cls,
default_config_path : typing.Optional[str] = None,
config_path_or_paths: typing.Union[str,list[str]] = None,
config_dict: typing.Optional[dict] = None,
settings_strs: typing.Optional[list[str]] = None,
):
'''Initialize a class instance using config files from disk, and/or a dictionary
of options, and/or overrides from the cli
'''

config_paths = []
if isinstance(config_path_or_paths, str):
config_paths.append(config_path_or_paths)
elif isinstance(config_path_or_paths, list):
config_paths.extend(config_path_or_paths)
if settings_strs is None:
settings_strs = []
raw_config = xconf._get_config_data(default_config_path, config_paths, settings_strs)
if config_dict is not None:
for key, value in config_dict.items():
if key in raw_config:
old_val = raw_config[key]
log.info(f"Using provided value {value} for {key} which was set to {old_val} in the loaded config files")
raw_config.update(config_dict)
try:
instance = xconf.from_dict(cls, raw_config)
except (xconf.UnexpectedDataError, xconf.MissingValueError) as e:
raise xconf.ConfigMismatch(e, raw_config)
return instance


class XDevice(Device):
prefix_dir : str = "/opt/MagAOX"
logs_dir : str = "logs"
config_dir : str = "config"
log : logging.Logger
config : dict
config : BaseConfig

def _init_config(self):
config_file = self.prefix_dir + "/" + self.config_dir + "/" + self.name + ".conf"
try:
with open(config_file, 'r') as fh:
self.config = toml.loads(fh)
except Exception:
log.exception(f"Could not load the config file (tried {config_file})")
self.config = {}
@classmethod
@property
def default_config_path(cls):
return cls.prefix_dir + "/" + cls.config_dir + "/" + cls.__name__ + ".conf"

@classmethod
def load_config(cls, filenames, overrides):
config_class : BaseConfig = typing.get_type_hints(cls)['config']
return config_class.from_config(cls.default_config_path, filenames, settings_strs=overrides)

def _init_logs(self, verbose, all_verbose):
self.log = logging.getLogger(self.name)
Expand Down Expand Up @@ -54,7 +95,7 @@ def _init_logs(self, verbose, all_verbose):
def __init__(self, name, *args, verbose=False, all_verbose=False, **kwargs):
fifos_root = self.prefix_dir + "/drivers/fifos"
super().__init__(name, *args, connection_class=partial(transports.IndiFifoConnection, name=name, fifos_root=fifos_root), **kwargs)
self._init_config()
self.config = self.load_config()
self._init_logs(verbose, all_verbose)

def lock_pid_file(self):
Expand Down Expand Up @@ -86,9 +127,17 @@ def main(self):
@classmethod
def console_app(cls):
import argparse
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(add_help=False)
xconf.add_subparser_arguments(parser)
parser.add_argument('-n', '--name', help="Device name for INDI")
parser.add_argument('-v', '--verbose', action='store_true', help="Set device log level to DEBUG")
parser.add_argument('-a', '--all-verbose', action='store_true', help="Set global log level to DEBUG")
args = parser.parse_args()
config_class = typing.get_type_hints(cls)['config']
if args.help:
xconf.print_help(config_class, parser)
sys.exit(0)
if args.dump_config:
config = cls.load_config(args.config_file, args.vars)
print(xconf.config_to_toml(config))
sys.exit(0)
cls(name=args.name, verbose=args.verbose, all_verbose=args.all_verbose).main()

0 comments on commit 3cacf3d

Please sign in to comment.