Skip to content

Commit

Permalink
Refactor Command execution. Many smaller bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
gr0vity committed May 8, 2023
1 parent cdd2202 commit c060dd6
Show file tree
Hide file tree
Showing 38 changed files with 615 additions and 294 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
recursive-include nanolab/snippets/ *
Empty file added nanolab/command/__init__.py
Empty file.
49 changes: 49 additions & 0 deletions nanolab/command/command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from abc import ABC, abstractmethod
from .mixins.bash_command_mixin import BashCommandMixin
from .mixins.snippet_command_mixin import SnippetCommandMixin
from .mixins.python_command_mixin import PythonCommandMixin
from .mixins.threaded_command_mixin import ThreadedCommandMixin
from nanolab.src.snippet_manager import SnippetManager


class ICommand(ABC):

@abstractmethod
def validate(self):
pass

@abstractmethod
def execute(self):
pass


class Command:

def __init__(self, command_config: dict, snippet_manager: SnippetManager):
self.command_config = command_config
self.snippet_manager = snippet_manager
self.mixins = {
'bash': BashCommandMixin,
'snippet': SnippetCommandMixin,
'python': PythonCommandMixin,
'threaded': ThreadedCommandMixin
}

command_type = self.command_config['type']

if command_type not in self.mixins:
raise ValueError(f"Unsupported command type '{command_type}'")

mixin = self.mixins[command_type](self)
self.mixin = mixin

def validate(self):
self.mixin.validate()

def execute(self):
self.mixin.execute()

def execute_another_command(self, command_config):
another_command = Command(command_config, self.snippet_manager)
another_command.validate()
another_command.execute()
9 changes: 9 additions & 0 deletions nanolab/command/command_validator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .command import Command


class CommandValidator:

@staticmethod
def validate_command(command_config: dict, snippets: dict = None):
command = Command(command_config, snippets)
command.validate()
Empty file.
29 changes: 29 additions & 0 deletions nanolab/command/mixins/base_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from os import environ
import inspect
import logging


class CommandMixinBase:

def __init__(self, command_instance):
self.command_instance = command_instance
self.logger = logging.getLogger(__name__)

def _get_completed_variables(self):
variables = self.command_instance.command_config.get('variables', {})

#add global variables
variables["docker_tag"] = environ["docker_tag"]
return variables

def _get_filtered_variables(self, method):
variables = self._get_completed_variables()
method_parameters = self._get_method_parameters(method)
return {
key: value
for key, value in variables.items() if key in method_parameters
}

def _get_method_parameters(self, method):
signature = inspect.signature(method)
return [param.name for param in signature.parameters.values()]
26 changes: 26 additions & 0 deletions nanolab/command/mixins/bash_command_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import subprocess
from .base_mixin import CommandMixinBase


class BashCommandMixin(CommandMixinBase):

def validate(self):
pass
# Validation logic for BashCommand

def execute(self):
variables = self._get_completed_variables()
command = self.command_instance.command_config['command'].format(
**variables)
process = subprocess.run(command,
shell=True,
text=True,
capture_output=True)

if process.returncode != 0:
print(
f"Error executing command: {command}\nError: {process.stderr.strip()}"
)
else:
response = process.stdout.strip() or process.stderr.strip()
print(response)
40 changes: 40 additions & 0 deletions nanolab/command/mixins/python_command_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from .base_mixin import CommandMixinBase
from nanolab import pycmd


class PythonCommandMixin(CommandMixinBase):

def validate(self):

if "method" not in self.command_instance.command_config:
raise ValueError("Python command: 'method' is required.")

method_name = self.command_instance.command_config["method"]

if "class" in self.command_instance.command_config:
cls = getattr(pycmd, self.command_instance.command_config["class"])
if not cls:
raise ValueError(
f"Python command: Class '{self.command_instance.command_config['class']}' not found."
)
if not hasattr(cls, method_name):
raise ValueError(
f"Python command: Method '{method_name}' not found in class '{self.command_instance.command_config['class']}'."
)
else:
if method_name not in globals():
raise ValueError(
f"Python command: Method '{method_name}' not found in the current module."
)

def execute(self):
class_name = self.command_instance.command_config.get(
"class", "NodeInteraction")
cls = getattr(pycmd, class_name)
instance = cls(**self.command_instance.command_config.get(
'constructor_params', {}))

method = getattr(instance,
self.command_instance.command_config['method'])
filtered_variables = self._get_filtered_variables(method)
method(**filtered_variables)
23 changes: 23 additions & 0 deletions nanolab/command/mixins/snippet_command_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from nanolab.src.snippet_manager import SnippetManager
from .base_mixin import CommandMixinBase


class SnippetCommandMixin(CommandMixinBase):

def validate(self):
snippet = self.command_instance.snippet_manager.get_snippet_by_key(
self.command_instance.command_config["key"])
missing_vars = set(snippet.get("mandatory_vars", set())) - set(
self.command_instance.command_config.get("variables", {}).keys())
if missing_vars:
raise KeyError(
f"Missing value(s) for mandatory variable(s): {', '.join(missing_vars)}"
)

def execute(self):
snippet = self.command_instance.snippet_manager.get_snippet_by_key(
self.command_instance.command_config["key"])

for snippet_command in snippet["commands"]:
snippet_command["variables"] = self._get_completed_variables()
self.command_instance.execute_another_command(snippet_command)
61 changes: 61 additions & 0 deletions nanolab/command/mixins/threaded_command_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import threading
from nanolab.src.snippet_manager import SnippetManager
from nanolab import pycmd
from .base_mixin import CommandMixinBase
from collections import defaultdict


class ThreadedCommandMixin(CommandMixinBase):

def _execute_command_sequence(self, commands):
for command_config in commands:
self.command_instance.execute_another_command(command_config)

def validate(self):
for python_command in self.command_instance.command_config["commands"]:
if "method" not in python_command:
raise ValueError(f"Python command: 'method' is required.")

method_name = python_command["method"]

if "class" in python_command:
cls = getattr(pycmd, python_command["class"])
if not cls:
raise ValueError(
f"Python command: Class '{python_command['class']}' not found."
)
if not hasattr(cls, method_name):
raise ValueError(
f"Python command: Method '{method_name}' not found in class '{python_command['class']}'."
)
else:
if method_name not in globals():
raise ValueError(
f"Python command: Method '{method_name}' not found in the current module."
)

def execute(self):
threads = []
command_groups = defaultdict(list)

for command_config in self.command_instance.command_config["commands"]:
group = command_config.get("group")
if group:
command_groups[group].append(command_config)
else:
thread = threading.Thread(
target=self.command_instance.execute_another_command,
args=(command_config, ))
threads.append(thread)

#execute these commands in sequence in one thread
for group_commands in command_groups.values():
thread = threading.Thread(target=self._execute_command_sequence,
args=(group_commands, ))
threads.append(thread)

for thread in threads:
thread.start()

for thread in threads:
thread.join()
20 changes: 10 additions & 10 deletions nanolab/data/download_data.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#download ledgers
wget -q --continue https://bnano.info/public/saved_ledgers/3pr_init.ldb -P nanolab/data/ledgers/ &
wget -q --continue https://bnano.info/public/saved_ledgers/6pr_init.ldb -P nanolab/data/ledgers/ &
wget -q --continue https://bnano.info/public/saved_ledgers/10pr_init.ldb -P nanolab/data/ledgers/ &
wget -q --continue https://bnano.info/public/saved_ledgers/6pr_bucket0-1-88-90-100_10kaccs.ldb -P nanolab/data/ledgers/ &
wget -q --continue https://bnano.info/public/saved_ledgers/10pr_bucket0-1-88-90-100_10kaccs.ldb -P nanolab/data/ledgers/
wget -q --continue https://bnano.info/public/saved_ledgers/3pr_init.ldb -P ledgers/ &
wget -q --continue https://bnano.info/public/saved_ledgers/6pr_init.ldb -P ledgers/ &
wget -q --continue https://bnano.info/public/saved_ledgers/10pr_init.ldb -P ledgers/ &
wget -q --continue https://bnano.info/public/saved_ledgers/6pr_bucket0-1-88-90-100_10kaccs.ldb -P ledgers/ &
wget -q --continue https://bnano.info/public/saved_ledgers/10pr_bucket0-1-88-90-100_10kaccs.ldb -P ledgers/

#download blocks
wget -q --continue https://bnano.info/public/saved_blocks/3node_net.bintree.50k.json -P nanolab/data/blocks/ &
wget -q --continue https://bnano.info/public/saved_blocks/6node_bintree_100k.json -P nanolab/data/blocks/ &
wget -q --continue https://bnano.info/public/saved_blocks/6node_buckets_0-1-88-90-100_10rounds.json -P nanolab/data/blocks/ &
wget -q --continue https://bnano.info/public/saved_blocks/10node_100k_bintree.json -P nanolab/data/blocks/ &
wget -q --continue https://bnano.info/public/saved_blocks/10node_bucket_rounds.json -P nanolab/data/blocks/
wget -q --continue https://bnano.info/public/saved_blocks/3node_net.bintree.50k.json -P blocks/ &
wget -q --continue https://bnano.info/public/saved_blocks/6node_bintree_100k.json -P blocks/ &
wget -q --continue https://bnano.info/public/saved_blocks/6node_buckets_0-1-88-90-100_10rounds.json -P blocks/ &
wget -q --continue https://bnano.info/public/saved_blocks/10node_100k_bintree.json -P blocks/ &
wget -q --continue https://bnano.info/public/saved_blocks/10node_bucket_rounds.json -P blocks/
Loading

0 comments on commit c060dd6

Please sign in to comment.