I am working on a code which aims to gather simulation commands and multiprocess them, sourcing a shell file for each subprocess before running a simulation command in the subprocess. For this I gather the commands in another function in a dictionary which is used by the functions below:
def source_shell_script(self, script_path: str) -> dict:
"""
Sources a shell script and updates the environment for each subprocess.
"""
if not os.path.exists(script_path):
raise FileNotFoundError(f"Script not found: {script_path}")
# source the script and output environment variables
command = f"bash -c 'source {script_path} && env'"
try:
# run the command and capture the output
result = subprocess.run(command, shell=True, stdout=subprocess.PIPE, text=True, check=True)
# parse the environment variables from the command output
env_vars = dict(
line.split("=", 1) for line in result.stdout.splitlines() if "=" in line
)
return env_vars
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Failed to source script: {script_path}. Error: {e}")
def run_cmd(self, cmd_px: tuple) -> None:
cmd, px_src_path = cmd_px
try:
# get environment variables
env_vars = self.source_shell_script(px_src_path)
print(f"Executing command: {cmd}")
result = subprocess.run(cmd, shell=True, env=env_vars, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print(f"Output: {result.stdout}")
if result.returncode != 0:
print(f"Error: {result.stderr}")
except Exception as e:
print(f"Failed to execute command: {cmd}. Error: {e}")
def exec_sim(self) -> None:
"""
Execute all simulations in parallel using multiprocessing.
"""
# create a list of (command, px_src_path) tuples for each pixel configuration
run_queue = [(cmd, self.sim_dict[px_key]["px_src_path"])
for px_key in self.sim_dict
for cmd in self.sim_dict[px_key]["px_ddsim_cmds"]]
num_workers = os.cpu_count() # number of processes
with multiprocessing.Pool(num_workers) as pool:
pool.map(self.run_cmd, run_queue)
if __name__ == "__main__":
# initialize program
eic_object = HandleEIC()
eic_object.init_path_var()
pixel_sizes = eic_object.setup_json()
eic_object.pixel_sizes = pixel_sizes
os.chmod(eic_object.execution_path, 0o777)
eic_object.setup_sim()
print("Simulation dictionary:", eic_object.sim_dict)
eic_object.exec_sim()
# create backup for simulation
eic_object.mk_sim_backup()
Instead of running properly, my program gets stuck and the console prints the commands:
Console output:
Simulation dictionary: {'2.0_0.1': {'px_epic_path': '/data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px/epic', 'px_compact_path': '/data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px/epic/install/share/epic/compact', 'px_ip6_path': '/data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px/epic/install/share/epic/epic_ip6_extended.xml', 'px_src_path': '/data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px/epic/install/bin/thisepic.sh', 'px_out_path': '/data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px', 'px_ddsim_cmds': ['ddsim --inputFiles /data/user/Analysis_epic_new/simulations/genEvents/results/beamEffectsElectrons_20.hepmc --outputFile /data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px/output_20edm4hep.root --compactFile /data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px/epic/install/share/epic/epic_ip6_extended.xml -N 5']}, '0.1_0.1': {'px_epic_path': '/data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px/epic', 'px_compact_path': '/data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px/epic/install/share/epic/compact', 'px_ip6_path': '/data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px/epic/install/share/epic/epic_ip6_extended.xml', 'px_src_path': '/data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px/epic/install/bin/thisepic.sh', 'px_out_path': '/data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px', 'px_ddsim_cmds': ['ddsim --inputFiles /data/user/Analysis_epic_new/simulations/genEvents/results/beamEffectsElectrons_20.hepmc --outputFile /data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px/output_20edm4hep.root --compactFile /data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px/epic/install/share/epic/epic_ip6_extended.xml -N 5']}}
Executing command: ddsim --inputFiles /data/user/Analysis_epic_new/simulations/genEvents/results/beamEffectsElectrons_20.hepmc --outputFile /data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px/output_20edm4hep.root --compactFile /data/user/Analysis_epic_new/simulations/simEvents/0.1x0.1px/epic/install/share/epic/epic_ip6_extended.xml -N 5
Executing command: ddsim --inputFiles /data/user/Analysis_epic_new/simulations/genEvents/results/beamEffectsElectrons_20.hepmc --outputFile /data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px/output_20edm4hep.root --compactFile /data/user/Analysis_epic_new/simulations/simEvents/2.0x0.1px/epic/install/share/epic/epic_ip6_extended.xml -N 5
Why is my code not running as expected? What am I doing wrong?
Kindly check now after these changes.
Changes:
1.The source_shell_script method sources the shell script and returns environment variables. These variables are passed into the subprocess.run call via the env parameter. If the script is missing, a FileNotFoundError is raised. If sourcing fails, a RuntimeError is raised.
2.The run_cmd method now checks for the return code of the subprocess. If the command fails (result.returncode != 0), the error is printed using stderr. Otherwise, it prints the output using stdout. If any exception occurs during the above process, it's caught and printed.
multiprocessing.Pool
to execute the commands in parallel, with each worker running run_cmd.4, The simulation dictionary holds the simulation details, including paths to the shell scripts and the commands to run. This (sim_dict) is assumed to be initialized in setup_json.
execution_path should exist and should have correct permissions (0o777)
Added more verbose logging (print) (to help trace command execution. Check the output and confirm if the paths and commands are coect.
7.Test the script with a simplified example first. Ensure that the paths to the shell scripts (px_src_path) and the simulation commands (px_ddsim_cmds) are correct.
import os
import subprocess
import multiprocessing
class SimulationHandler:
def __init__(self):
self.sim_dict = {}
def get_path(self, *path_components):
"""Joins path components into a single file path."""
return os.path.join(*path_components)
def source_shell_script(self, *path_components) -> dict:
"""Sources a shell script and returns the environment variables as a dictionary."""
script_path = self.get_path(*path_components)
if not os.path.exists(script_path):
raise FileNotFoundError(f'Script not found: {script_path}')
command = ['bash', '-c', 'source "$1" && env', 'bash', script_path]
try:
result = subprocess.run(command, stdout=subprocess.PIPE, text=True, check=True)
env_vars = dict(
line.split('=', 1) for line in result.stdout.splitlines() if '=' in line
)
return env_vars
except subprocess.CalledProcessError as e:
raise RuntimeError(f'Failed to source script: {script_path}. Error: {e}')
def run_cmd(self, cmd_px: tuple) -> None:
"""Executes a command with environment variables sourced from a shell script."""
cmd, script_dir, script_name = cmd_px
try:
env_vars = self.source_shell_script(script_dir, script_name)
print(f'Executing command: {cmd}')
result = subprocess.run(
cmd.split(),
env=env_vars,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
print(f'Output: {result.stdout}')
if result.returncode != 0:
print(f'Error: {result.stderr}')
except Exception as e:
print(f'Failed to execute command: {cmd}. Error: {e}')
def exec_sim(self) -> None:
"""Executes all simulations in parallel using multiprocessing."""
run_queue = [
(cmd, self.sim_dict[px_key]['script_dir'], self.sim_dict[px_key]['script_name'])
for px_key in self.sim_dict
for cmd in self.sim_dict[px_key]['commands']
]
num_workers = os.cpu_count() # Number of processes
with multiprocessing.Pool(num_workers) as pool:
pool.map(self.run_cmd, run_queue)
if __name__ == '__main__':
handler = SimulationHandler()
# Example simulation dictionary for demonstration
handler.sim_dict = {
'config_1': {
'script_dir': '/data/user/Analysis_epic_new/simulations/simEvents/config_1/epic/install/bin',
'script_name': 'thisepic.sh',
'commands': [
'ddsim --inputFiles input1.hepmc --outputFile output1.root --compactFile epic_ip6_extended.xml -N 5'
],
},
'config_2': {
'script_dir': '/data/user/Analysis_epic_new/simulations/simEvents/config_2/epic/install/bin',
'script_name': 'thisepic.sh',
'commands': [
'ddsim --inputFiles input2.hepmc --outputFile output2.root --compactFile epic_ip6_extended.xml -N 5'
],
},
}
# Execute simulations
handler.exec_sim()
Edit: Reasons for the unexpected behavior:
For focus and hover behavior, rasio-button like widgets behave differently. For eg., When hovered, a Radiobutton might display a different border or background color by default, depending on the platform and theme. Your code hasn't given style for hover or focus effects, so the default behavior is being used.
You're setting bg="#292d2e" for both Radiobutton and Label, but the Radiobutton itself might override some parts of the style when hovered (like its default border or highlight background). These overrides could result in visual artifacts.
The default behavior of widgets like Radiobutton can vary slightly across platforms (Windows, macOS, Linux), leading to hover effects you might not expect: Some themes or window managers have hover effects enabled by default for interactive widgets like buttons and radiobuttons.