Skip to content

Commit

Permalink
Merge pull request #31 from autolab-project/v2.0rc1
Browse files Browse the repository at this point in the history
V2.0rc1
  • Loading branch information
Python-simulation authored Jul 10, 2024
2 parents df2469e + f0fef6d commit f37d136
Show file tree
Hide file tree
Showing 52 changed files with 3,841 additions and 1,600 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
[![PyPi](https://img.shields.io/pypi/v/autolab)](https://pypi.org/project/autolab/)
[![Documentation Status](https://readthedocs.org/projects/autolab/badge/?version=latest)](https://autolab.readthedocs.io/en/latest/?badge=latest)

# Autolab
__Python package for scientific experiments automation__

The purpose of this package it to provide easy and efficient tools to deal with your scientific instruments, and to run automated experiments with them, by command line instructions or through a graphical user interface (GUI).

Created by Quentin Chateiller, Python drivers originally from Quentin Chateiller and Bruno Garbin, for the C2N-CNRS (Center for Nanosciences and Nanotechnologies, Palaiseau, France) ToniQ team.
Project continued by Jonathan Peltier, for the C2N-CNRS, Minaphot team.
Project continued by Jonathan Peltier, for the C2N-CNRS Minaphot team and Mathieu Jeannin, for the C2N-CNRS Odin team.

Project hosted at https://github.com/autolab-project/autolab

Expand Down
12 changes: 5 additions & 7 deletions autolab/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# -*- coding: utf-8 -*-
"""
Created on Fri May 17 15:04:04 2019
Python package for scientific experiments automation
The purpose of this package it to provide easy and efficient tools to deal with your scientific instruments, and to run automated experiments with them, by command line instructions or through a graphical user interface (GUI).
Created by Quentin Chateiller, Python drivers originally from Quentin Chateiller and Bruno Garbin, for the C2N-CNRS (Center for Nanosciences and Nanotechnologies, Palaiseau, France) ToniQ team.
Project continued by Jonathan Peltier, for the C2N-CNRS, Minaphot team.
Project continued by Jonathan Peltier, for the C2N-CNRS Minaphot team and Mathieu Jeannin, for the C2N-CNRS Odin team.
Project hosted at https://github.com/autolab-project/autolab
Expand All @@ -31,7 +29,7 @@

# Load user config
from .core import config as _config
first = _config.initialize_local_directory()
FIRST = _config.initialize_local_directory()
_config.check_autolab_config()
_config.check_plotter_config()
_config.set_temp_folder()
Expand All @@ -56,7 +54,7 @@
from .core.server import Server as server

# GUI
from .core.gui import start as gui
from .core.gui import gui, plotter, monitor, slider, add_device, about, variables_menu

# Repository
from .core.repository import install_drivers
Expand All @@ -68,10 +66,10 @@

from .core._create_shortcut import create_shortcut

if first:
if FIRST:
# Ask if create shortcut
create_shortcut(ask=True)
del first
del FIRST

# Loading the drivers informations on startup
_drivers.update_drivers_paths()
Expand Down
27 changes: 14 additions & 13 deletions autolab/_entry_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ def print_help():
print()
print('Commands:')
print(' gui Start the Graphical User Interface')
print(' plotter Start the Plotter')
print(' add_device Start add device menu')
print(' install_drivers Install drivers from GitHub')
print(' driver Driver interface')
print(' device Device interface')
Expand Down Expand Up @@ -48,20 +50,19 @@ def main():
args = [f'autolab {command}'] + args[2: ] # first is 'autolab' and second is command
sys.argv = args

if command == 'doc': # Open help on read the docs
autolab.doc()
elif command == 'report': # Open github report issue webpage
autolab.report()
elif command == 'gui': # GUI
autolab.gui()
elif command == 'infos':
autolab.infos()
elif command == 'install_drivers':
autolab.install_drivers()
elif command == 'driver':
# Removed bellow and similar because getattr will get every standard command (only difference is now it raises error if gives too much arguments)
# if command == 'gui':
# autolab.gui()
if command == 'driver':
driver_parser(args)
elif command == 'device':
device_parser(args)
elif command in dir(autolab): # Execute autolab.command if exists
attr = getattr(autolab, command)
if hasattr(attr, '__call__'):
attr(*args[1: ])
else:
print(attr)
else:
print(f"Command {command} not known. Autolab doesn't have Super Cow Power... yet ^^")

Expand Down Expand Up @@ -163,14 +164,14 @@ def driver_parser(args_list: List[str]):

# Instantiation of driver.py and driver_utilities.py
global driver_instance
assert 'connection' in config.keys(), f"Must provide a connection for the driver using -C connection with connection being for this driver among {autolab._drivers.get_connection_names(autolab._drivers.load_driver_lib(driver_name))}"
assert 'connection' in config, f"Must provide a connection for the driver using -C connection with connection being for this driver among {autolab._drivers.get_connection_names(autolab._drivers.load_driver_lib(driver_name))}"
driver_instance = autolab.get_driver(driver_name, **config)

if driver_name in autolab._config.list_all_devices_configs():
# Load config object
config = dict(autolab._config.get_device_config(driver_name))
# Check if driver provided
assert 'driver' in config.keys(), f"Driver name not found in driver config '{driver_name}'"
assert 'driver' in config, f"Driver name not found in driver config '{driver_name}'"
driver_name = config['driver']

driver_utilities = autolab._drivers.load_driver_utilities_lib(driver_name + '_utilities')
Expand Down
Binary file modified autolab/autolab.pdf
Binary file not shown.
30 changes: 14 additions & 16 deletions autolab/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

import os
import tempfile
import configparser
from typing import List
from . import paths
Expand All @@ -19,7 +20,7 @@
def initialize_local_directory() -> bool:
""" This function creates the default autolab local directory.
Returns True if create default autolab folder (first autolab use) """
first = False
FIRST = False
_print = True
# LOCAL DIRECTORY
if not os.path.exists(paths.USER_FOLDER):
Expand All @@ -30,7 +31,7 @@ def initialize_local_directory() -> bool:
"It also contains the 'driver' directory with 'official' and 'local' sub-directories."
)
_print = False
first = True
FIRST = True

# DEVICES CONFIGURATION FILE
if not os.path.exists(paths.DEVICES_CONFIG):
Expand Down Expand Up @@ -62,7 +63,7 @@ def initialize_local_directory() -> bool:
save_config('plotter', configparser.ConfigParser())
if _print: print(f'The configuration file plotter_config.ini has been created: {paths.PLOTTER_CONFIG}')

return first
return FIRST


def save_config(config_name, config):
Expand Down Expand Up @@ -137,15 +138,14 @@ def check_autolab_config():
# 'plotter': {'precision': 10},
}

for section_key in autolab_dict.keys():
dic = autolab_dict[section_key]
for section_key, section_dic in autolab_dict.items():
if section_key in autolab_config.sections():
conf = dict(autolab_config[section_key])
for key in dic.keys():
if key not in conf.keys():
conf[key] = str(dic[key])
for key, dic in section_dic.items():
if key not in conf:
conf[key] = str(dic)
else:
conf = dic
conf = section_dic

autolab_config[section_key] = conf

Expand Down Expand Up @@ -220,7 +220,6 @@ def set_temp_folder() -> str:
temp_folder = get_directories_config()["temp_folder"]

if temp_folder == 'default':
import tempfile
# Try to get TEMP, if not get tempfile
temp_folder = os.environ.get('TEMP', tempfile.gettempdir())

Expand Down Expand Up @@ -271,15 +270,14 @@ def check_plotter_config():
'device': {'address': 'dummy.array_1D'},
}

for section_key in plotter_dict.keys():
dic = plotter_dict[section_key]
for section_key, section_dic in plotter_dict.items():
if section_key in plotter_config.sections():
conf = dict(plotter_config[section_key])
for key in dic.keys():
if key not in conf.keys():
conf[key] = str(dic[key])
for key, dic in section_dic.items():
if key not in conf:
conf[key] = str(dic)
else:
conf = dic
conf = section_dic

plotter_config[section_key] = conf

Expand Down
39 changes: 28 additions & 11 deletions autolab/core/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
@author: quentin.chateiller
"""

from typing import List
from typing import List, Union

from . import drivers
from . import config
from .elements import Module
from .elements import Module, Element

# Storage of the devices
DEVICES = {}
Expand All @@ -27,13 +27,25 @@ def __init__(self, device_name: str, instance, device_config: dict):
self.device_config = device_config # hidden from completion
self.driver_path = drivers.get_driver_path(device_config["driver"])

Module.__init__(self, None, {'name': device_name, 'object': instance,
'help': f'Device {device_name} at {self.driver_path}'})
super().__init__(None, {'name': device_name, 'object': instance,
'help': f'Device {device_name} at {self.driver_path}'})

def close(self):
""" This function close the connection of the current physical device """
# Remove read and write signals from gui
try:
# condition avoid reopenning connection if use close twice
if self.name in DEVICES:
for struc in self.get_structure():
element = get_element_by_address(struc[0])
if struc[1] == 'variable':
element._read_signal = None
element._write_signal = None
except: pass

try: self.instance.close()
except: pass

del DEVICES[self.name]

def __dir__(self):
Expand All @@ -46,11 +58,16 @@ def __dir__(self):
# DEVICE GET FUNCTION
# =============================================================================

def get_element_by_address(address: str) -> Device:
""" Returns the Element located at the provided address """
def get_element_by_address(address: str) -> Union[Element, None]:
""" Returns the Element located at the provided address if exists """
address = address.split('.')
try:
element = get_device(address[0])
device_name = address[0]
if device_name in DEVICES:
element = DEVICES[device_name]
else:
# This should not be used on autolab closing to avoid access violation due to config opening
element = get_device(device_name)
for addressPart in address[1: ]:
element = getattr(element, addressPart.replace(" ", ""))
return element
Expand All @@ -70,12 +87,12 @@ def get_final_device_config(device_name: str, **kwargs) -> dict:
device_config[key] = value

# And the argument connection has to be provided
assert 'driver' in device_config.keys(), f"Missing driver name for device '{device_name}'"
assert 'driver' in device_config, f"Missing driver name for device '{device_name}'"

if device_config['driver'] == 'autolab_server':
device_config['connection'] = 'USELESS_ENTRY'

assert 'connection' in device_config.keys(), f"Missing connection type for device '{device_name}'"
assert 'connection' in device_config, f"Missing connection type for device '{device_name}'"

return device_config

Expand Down Expand Up @@ -103,7 +120,7 @@ def get_device(device_name: str, **kwargs) -> Device:

def list_loaded_devices() -> List[str]:
''' Returns the list of the loaded devices '''
return list(DEVICES.keys())
return list(DEVICES)


def list_devices() -> List[str]:
Expand All @@ -124,7 +141,7 @@ def get_devices_status() -> dict:
# CLOSE DEVICES
# =============================================================================

def close(device: Device = "all"):
def close(device: Union[str, Device] = "all"):
""" Close a device by providing its name or its instance. Use 'all' to close all openned devices. """

if str(device) == "all":
Expand Down
Loading

0 comments on commit f37d136

Please sign in to comment.