Skip to content

Commit

Permalink
Merge pull request #2 from ricardoedgarsilva/testing
Browse files Browse the repository at this point in the history
Version 0.5.0 launch
  • Loading branch information
ricardoedgarsilva authored Jun 14, 2023
2 parents 1531d40 + d141d54 commit 79324a7
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 138 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
data
test.py
measurements/__pycache__
instruments/__pycache__
instruments/__pycache__
build
dist
102 changes: 56 additions & 46 deletions PyCharMem.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import pyvisa
import numpy as np
import pyqtgraph as pg
from openpyxl.drawing.image import Image
from art import text2art
from rich.console import Console
from rich.traceback import install
Expand All @@ -27,7 +26,7 @@
# Global Variables
PROGRAM_INFO = {
'name': 'PyCharMem',
'version': '0.0.3',
'version': '0.0.5',
'author': 'Ricardo E. Silva',
'email': '[email protected]',
'description': 'PyCharMem is a Python program that allows you to measure the charge memory of a device.',
Expand All @@ -36,36 +35,37 @@
}


def verbose_debug(verbose: bool) -> logging.Logger:
def verbose_debug(verbose):
log_level = "NOTSET" if verbose else 'INFO'
logging.basicConfig(level=log_level, format="%(message)s", datefmt="[%X]", handlers=[RichHandler()])
return logging.getLogger("rich")


def clear_terminal() -> None:
def clear_terminal():
os.system('cls||clear')


def print_newlines(lines: int) -> None:
def print_newlines(lines):
print(lines * "\n")


def splash_screen(console: Console) -> None:
def splash_screen(console):
print(text2art(PROGRAM_INFO['name']))
console.print(f"Version: {PROGRAM_INFO['version']}", style='bold blue')
console.print(f"Repositoty: {PROGRAM_INFO['url']}", style='bold blue')
console.print(f"Author: {PROGRAM_INFO['author']}", style='bold blue')
print_newlines(5)


def open_config(logger: logging.Logger) -> None:
def open_config(logger):
try:
os.system({'Windows': 'start config.yml', 'Darwin': 'open config.yml', 'Linux': 'open config.yml'}.get(platform.system(), ''))
except:
logger.critical('Config file not found')
sys.exit()


def read_config(logger: logging.Logger) -> dict:
def read_config(logger):
try:
with open('config.yml', 'r') as file:
config = yaml.safe_load(file)
Expand All @@ -76,37 +76,37 @@ def read_config(logger: logging.Logger) -> dict:
sys.exit()


def path_exists(path: str) -> bool:
def path_exists(path):
return os.path.exists(path)


def get_path() -> str:
def get_path():
return os.path.dirname(os.path.realpath(__file__))


def mkdir(logger: logging.Logger, path: str) -> None:
def mkdir(logger, path):
if not path_exists(path):
os.makedirs(path)
logger.debug(f'Folder {path} created')


def get_index(path: str) -> int:
def get_index(path):
return len(os.listdir(path))


def get_filename(path: str, sample: str, device: str) -> str:
def get_filename(path, sample, device):
index = get_index(path)
date = datetime.datetime.now().strftime('%Y%m%d')
return f'{date}_{sample}_{device}_{index}.xlsx'


def get_available_addresses() -> list:
def get_available_addresses():
rm = pyvisa.ResourceManager()
addresses = rm.list_resources()
return addresses


def print_available_addresses(logger: logging.Logger, console: Console, addresses: list) -> None:
def print_available_addresses(logger, console, addresses):
print_newlines(1)
console.print(Panel.fit("[bold]Available Addresses[/bold]", border_style="green"))

Expand All @@ -117,13 +117,13 @@ def print_available_addresses(logger: logging.Logger, console: Console, addresse
console.print(address)


def check_address(logger: logging.Logger, addresses: list, address: str) -> None:
def check_address(logger, addresses, address):
if address not in addresses:
logger.critical('Instrument address in config file not found! Please edit config file with correct address')
sys.exit()


def check_missing_params(logger: logging.Logger, my_dict: dict, my_list: list) -> None:
def check_missing_params(logger, my_dict, my_list):
missing_items = [item for item in my_list if item not in my_dict]

if len(missing_items) == 0:
Expand All @@ -135,7 +135,7 @@ def check_missing_params(logger: logging.Logger, my_dict: dict, my_list: list) -
sys.exit()


def create_list(logger: logging.Logger, condition_values: list) -> np.ndarray:
def create_list(logger, condition_values):
cycle, max_value, min_value, step = condition_values
listp_oneway = np.arange(0, max_value, step)
listn_oneway = np.arange(0, min_value, -step)
Expand All @@ -150,10 +150,10 @@ def create_list(logger: logging.Logger, condition_values: list) -> np.ndarray:
sys.exit()


def get_datetime() -> str:
def get_datetime():
return datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S:%f')

def import_module(logger: logging.Logger, type: str, inst_type=None, measurement_type=None) -> type:
def import_module(logger, type, inst_type=None, measurement_type=None):
file_name, obj_name = '', ''

if type == 'instrument':
Expand All @@ -172,7 +172,7 @@ def import_module(logger: logging.Logger, type: str, inst_type=None, measurement
logger.debug(f'{obj_name} class imported')
return obj

def menu(logger: logging.Logger, console: Console, type: str) -> str:
def menu(logger, console, type):
name, message, choices = '', '', []

if type == 'main':
Expand Down Expand Up @@ -203,32 +203,32 @@ def menu(logger: logging.Logger, console: Console, type: str) -> str:
logger.debug(f'Returning answer: {answer}')
return answer['choice']

def ask_for_comment(logger: logging.Logger) -> str:
def ask_for_comment(logger):
print_newlines(2)
comment = [inquirer.Text('comment', message="What would you like to comment?", validate=lambda _, x: len(x) > 0),]
answer = inquirer.prompt(comment)
logger.debug(f'Comment: {answer}')
return answer['comment']

def repeat_measurement(logger: logging.Logger, console: Console) -> bool:
def repeat_measurement(logger, console):
print_newlines(2)
comment = [inquirer.Confirm('repeat', message="Would you like to repeat the measurement?")]
answer = inquirer.prompt(comment)
logger.debug(f'Repeat: {answer}')
return answer['repeat']

def exit(logger: logging.Logger, inst: object) -> None:
def exit(logger, inst):
logger.info('Exiting program...')
inst.close(logger)
logger.info('Instrument closed')
time.sleep(2)



# Important Classes

class FileSave:
def __init__(self, logger: logging.Logger, sample: str, device: str):
self.path = os.path.join(get_path(), "data", sample, device)
def __init__(self, logger, path, sample, device):
self.path = os.path.join(path, sample, device)
mkdir(logger, self.path)

self.file_name = get_filename(self.path, sample, device)
Expand All @@ -239,7 +239,7 @@ def __init__(self, logger: logging.Logger, sample: str, device: str):
self.wb.remove(self.wb['Sheet'])
self.wb.save(self.file_path)

def save_config(self, logger: logging.Logger, config: dict, measurement_type: str):
def save_config(self, logger, config, measurement_type):
self.ws = self.wb['config']

sections = ['sample', 'instrument', measurement_type]
Expand All @@ -251,14 +251,14 @@ def save_config(self, logger: logging.Logger, config: dict, measurement_type: st
self.wb.save(self.file_path)
logger.debug('Configuration file saved in config sheet')

def save_headers(self, logger: logging.Logger, headers_list: list):
def save_headers(self, logger, headers_list):
self.ws = self.wb['data']
for i in range(len(headers_list)):
self.ws.cell(row=1, column=i + 1).value = headers_list[i]
self.wb.save(self.file_path)
logger.debug('Headers saved in data sheet')

def save_result(self, logger: logging.Logger, result: list):
def save_result(self, logger, result):
self.ws = self.wb['data']
row = self.ws.max_row + 1
for i in range(len(result)):
Expand All @@ -269,8 +269,8 @@ def save_result(self, logger: logging.Logger, result: list):


class Logbook:
def __init__(self, logger: logging.Logger, sample: str):
self.path = os.path.join(get_path(), "data", sample)
def __init__(self, logger, path, sample):
self.path = os.path.join(path, sample)
mkdir(logger, self.path)

self.file_path = os.path.join(self.path, 'logbook.xlsx')
Expand All @@ -292,7 +292,7 @@ def __init__(self, logger: logging.Logger, sample: str):
self.wb.save(self.file_path)
logger.debug('Logbook file created')

def save_log(self, logger: logging.Logger, date: str, file: str, comment: str):
def save_log(self, logger, date, file, comment):
self.ws = self.wb['logbook']
row = self.ws.max_row + 1
self.ws.cell(row=row, column=1).value = date
Expand All @@ -307,13 +307,13 @@ class MeasurementThread(QThread):
clear_plots = pyqtSignal(list, list)
close_window = pyqtSignal()

def __init__(self, logger, inst, meas, config):
def __init__(self, logger, inst, meas, config, filesave):
super().__init__()
self.logger = logger
self.inst = inst
self.meas = meas
self.config = config
self.filesave = FileSave(logger, config.get('sample').get('name'), config.get('sample').get('device'))
self.filesave = filesave
self.filesave.save_config(logger, config, meas.name)
self.filesave.save_headers(logger, self.meas.headers)
self.n_cycles = config.get(meas.name).get('n_cycles')
Expand All @@ -337,21 +337,16 @@ def run(self):
progress.update(value_task, advance=-self.n_vals, description=f"[purple]Value 0/{self.n_vals}")
progress.update(cycle_task, advance=1, description=f"[blue]Cycle {cycle}/{self.n_cycles}")
self.inst.set_output_state(self.logger,'OFF')
self.logger.info('Measurement finished! Please close the window to continue.')


logbook = Logbook(self.logger, self.config.get('sample').get('name'))
self.logger.info('Measurement finished! Please enter a comment for the logbook')
comment = ask_for_comment(self.logger)
logbook.save_log(self.logger, get_datetime(), self.filesave.file_name, comment)
self.close_window.emit()
self.logger.info('Logbook saved!')


class MeasurementWindow(QMainWindow):
def __init__(self, logger, inst, meas, config):
def __init__(self, logger, inst, meas, config, filesave):
super().__init__()
self.initUI(meas)
self.measure = MeasurementThread(logger, inst, meas, config)
self.measure = MeasurementThread(logger, inst, meas, config, filesave)
self.measure.update_data.connect(self.update_data)
self.measure.clear_plots.connect(self.clear_plots)
self.measure.close_window.connect(self.close)
Expand Down Expand Up @@ -421,11 +416,11 @@ def close_window(self):

# Main Functions ------------------------------------------------------------------

def start_gui(logger: logging.Logger, inst: object, meas: object, config: dict):
def start_gui(logger, inst, meas, config, filesave):
app = QApplication(sys.argv)
app.setStyle(QStyleFactory.create("Fusion"))
app.setStyleSheet("QMainWindow::title {background-color: #333333;}")
window = MeasurementWindow(logger, inst, meas, config)
window = MeasurementWindow(logger, inst, meas, config, filesave)
window.show()
app.exec()

Expand Down Expand Up @@ -472,9 +467,24 @@ def main():
meas_class = import_module(logger=logger, type='measurement', measurement_type=option2)
meas = meas_class(logger, config, inst)

filesave = FileSave(logger, config.get('sample').get('path'), config.get('sample').get('name'), config.get('sample').get('device'))

check_missing_params(logger, meas.params[meas.name], meas.nparams)
logger.info('All parameters present')
start_gui(logger, inst, meas, config)
start_gui(logger, inst, meas, config, filesave)

path = config.get('sample').get('path')
sample_name = config.get('sample').get('name')
sample_device = config.get('sample').get('device')

logbook = Logbook(logger,path, sample_name)

logger.info('Please enter a comment for the logbook')
comment = ask_for_comment(logger)
logbook.save_log(logger, get_datetime(), filesave.file_name, comment)
logger.info('Logbook saved!')


option3 = repeat_measurement(logger, console)
if option3: continue
else:
Expand Down
50 changes: 0 additions & 50 deletions PyCharMem.spec

This file was deleted.

Loading

0 comments on commit 79324a7

Please sign in to comment.