Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
149 commits
Select commit Hold shift + click to select a range
ded924b
WIP cluster object
paxtonfitzpatrick Oct 31, 2020
dbbcdff
add mappings to mirror os.environ
paxtonfitzpatrick Oct 31, 2020
72b9aa0
WIP RemoteProcess class
paxtonfitzpatrick Oct 31, 2020
9af277c
updated requirements with min versions
paxtonfitzpatrick Oct 31, 2020
da2a03d
added typing
paxtonfitzpatrick Oct 31, 2020
91d1985
reorganized for installable package setup
paxtonfitzpatrick Nov 1, 2020
0ceef19
setup scripts
paxtonfitzpatrick Nov 1, 2020
2be3a65
finished setup scripts
paxtonfitzpatrick Nov 1, 2020
af6a11f
Merge branch 'master' of https://github.com/ContextLab/cluster-tools-…
paxtonfitzpatrick Nov 10, 2020
9023b21
renamed main module
paxtonfitzpatrick Nov 10, 2020
1889e52
renamed importable
paxtonfitzpatrick Nov 11, 2020
5567130
renamed and reorganized main cluster module
paxtonfitzpatrick Nov 11, 2020
8622704
separated typing-related definitions for clarity
paxtonfitzpatrick Nov 11, 2020
8f0c403
refactor: rename importable package
paxtonfitzpatrick Nov 11, 2020
ecc3083
skeleton exceptions module
paxtonfitzpatrick Nov 11, 2020
098e14e
moved to _extras submodule
paxtonfitzpatrick Nov 11, 2020
95df8f8
separate RemoteProcess class
paxtonfitzpatrick Nov 11, 2020
de4f88a
MultiStreamWrapper class for streaming stdout/stderr to multiple loca…
paxtonfitzpatrick Nov 11, 2020
eddb7c2
big update to RemoteProcess class, wrote AttrObserver
paxtonfitzpatrick Nov 11, 2020
201fd6e
SshProcessError class
paxtonfitzpatrick Nov 11, 2020
72543a1
remove unused imports
paxtonfitzpatrick Nov 11, 2020
6218f5e
some debugging and fixes
paxtonfitzpatrick Nov 11, 2020
1c6c31f
switched to threaded monitoring, added a few convenience functions
paxtonfitzpatrick Nov 14, 2020
42a1e77
reorganized some typing
paxtonfitzpatrick Nov 15, 2020
c90c2d8
allow user callback to return value, be called manually
paxtonfitzpatrick Nov 15, 2020
469b94e
exception handling for errors in remote process
paxtonfitzpatrick Nov 15, 2020
338ee0f
write shell command interface
paxtonfitzpatrick Nov 15, 2020
cedfe73
changed default allow_error value + other small changes
paxtonfitzpatrick Nov 15, 2020
e6bad1a
wrote file system navigation methods
paxtonfitzpatrick Nov 15, 2020
2d75abf
wrote file transfer methods
paxtonfitzpatrick Nov 15, 2020
440ff14
renamed "_extras" to "shared"
paxtonfitzpatrick Nov 15, 2020
1085cbd
started BatchSubmission class
paxtonfitzpatrick Nov 15, 2020
afa3e1e
some reorganizing
paxtonfitzpatrick Nov 15, 2020
a0d6fef
checkpoint pre-refactor of Cluster class
paxtonfitzpatrick Nov 15, 2020
c25f49d
gitignore build artifacts
paxtonfitzpatrick Nov 15, 2020
3dbc59a
major refactor of SshShell object
paxtonfitzpatrick Nov 26, 2020
fedd074
moved shell-related code to subdir
paxtonfitzpatrick Nov 29, 2020
1a7c2c4
clearer delineation between Path and PurePath objects
paxtonfitzpatrick Nov 29, 2020
4918990
add SSHConnectionError
paxtonfitzpatrick Dec 2, 2020
b58dc9e
rename SshProcessError -> SSHProcessError
paxtonfitzpatrick Dec 2, 2020
503e833
moved old helpers file to old/ and created new helpers
paxtonfitzpatrick Dec 2, 2020
e25ac98
remove ShellEnvironMixin and move methods to BaseShell classs
paxtonfitzpatrick Dec 4, 2020
93caeff
WIP major refactor of Cluster and Shell-related classes.
paxtonfitzpatrick Dec 4, 2020
8a4a5d5
moved environ.py to shells dir, delete mixins dir
paxtonfitzpatrick Dec 4, 2020
691fe58
finished file system interface methods
paxtonfitzpatrick Dec 5, 2020
0b9c6ec
read/write text/bytes methods
paxtonfitzpatrick Dec 5, 2020
b076552
finished full prototype shell interface
paxtonfitzpatrick Dec 5, 2020
d4ef933
minor cleanup
paxtonfitzpatrick Dec 5, 2020
3e44543
some cleanup and groundwork for Cluster support classes
paxtonfitzpatrick Dec 5, 2020
efdaf60
enforce types in PseudoEnviron
paxtonfitzpatrick Dec 5, 2020
67b3b44
added caching for proeprties and made some changes to default args
paxtonfitzpatrick Dec 5, 2020
03ed03b
moved template scripts outside of main package dir
paxtonfitzpatrick Dec 5, 2020
05e3a67
add ClusterProjectError exception class
paxtonfitzpatrick Dec 5, 2020
9adb954
minor fixes to Shell classes for resolving local and remote paths
paxtonfitzpatrick Dec 5, 2020
c0e9dcc
submodule skeleton for Project classes & related subclasses/mixins
paxtonfitzpatrick Dec 5, 2020
01d1d07
template config files
paxtonfitzpatrick Dec 8, 2020
9a93e81
class for representing project scripts (cruncher, collector, etc.)
paxtonfitzpatrick Dec 8, 2020
2d46134
WIP revamping Cluster object
paxtonfitzpatrick Dec 8, 2020
f718d38
base class for files that are synced between local and remote
paxtonfitzpatrick Dec 8, 2020
9d33ce5
classes for interacting with config files
paxtonfitzpatrick Dec 8, 2020
5e65456
minor cleanup and notes
paxtonfitzpatrick Dec 8, 2020
3211baa
reorganized submodules
paxtonfitzpatrick Dec 8, 2020
7671c19
add manifest file to template configs & scripts are included
paxtonfitzpatrick Dec 9, 2020
da47ef6
moved templates dir inside src directory
paxtonfitzpatrick Dec 9, 2020
484a4ec
AttributeConfig class for managing config file interface
paxtonfitzpatrick Dec 9, 2020
e8f0ec7
fixed a weird indentation issue
paxtonfitzpatrick Dec 9, 2020
de50b96
added overrides for a few extra dict methods for safe assignment
paxtonfitzpatrick Dec 9, 2020
55180dc
enforce type consistency when updating values
paxtonfitzpatrick Dec 9, 2020
ccd46ac
basic config parsing and WIP config object subclasses
paxtonfitzpatrick Dec 9, 2020
ef01b26
cleaned up PseudoEnviron and added MonitoredEnviron
paxtonfitzpatrick Dec 9, 2020
6c4e96c
updated AttributeConfig to take a callback function for updates to co…
paxtonfitzpatrick Dec 9, 2020
89f5b13
finished (?) BaseConfig class
paxtonfitzpatrick Dec 9, 2020
e03c8c1
FINALLY full family of config file handlers and support classes (most…
paxtonfitzpatrick Dec 9, 2020
dd38599
big throw-everything-together checkpoint commit with a bunch of minor…
paxtonfitzpatrick Dec 10, 2020
74cd1cf
add __getattr__ and __getitem__ methods to allow access to _config fi…
paxtonfitzpatrick Dec 11, 2020
d18d20f
some changes/simplifications to how self.port and other connection pa…
paxtonfitzpatrick Dec 12, 2020
3d4f2ca
some fixes to spawn_process
paxtonfitzpatrick Dec 12, 2020
64c7599
some tweaks to how changing directory is validated
paxtonfitzpatrick Dec 12, 2020
4a223bd
added some fields to global and project configs
paxtonfitzpatrick Dec 12, 2020
182dfb8
major update to TrackedAttrConfig object with bug fixes, validation, …
paxtonfitzpatrick Dec 12, 2020
06045dc
__setattr__ & __setitem__ methods for accessing config object directly
paxtonfitzpatrick Dec 12, 2020
987ca15
module for config attr update hook functions & helper decorator to bi…
paxtonfitzpatrick Dec 12, 2020
fd2ae0e
implemented importing, binding, and assigning attribute hooks on conf…
paxtonfitzpatrick Dec 12, 2020
2e8cd4d
minor tweaks to formatting and some notes & reminders for later
paxtonfitzpatrick Dec 12, 2020
8e12855
moved data_subdir and script_subdir fields to project-specific config…
paxtonfitzpatrick Dec 12, 2020
9a67f63
tweaked approach to representing ProjectScripts
paxtonfitzpatrick Dec 12, 2020
3815b59
reworked logic of setting self.cwd after connecting, WIP outlines of …
paxtonfitzpatrick Dec 12, 2020
6f159c8
added MonitoredList class for tracking list values in config
paxtonfitzpatrick Dec 13, 2020
562de97
cleaned up and added notes
paxtonfitzpatrick Dec 13, 2020
d326f60
added logic for modules list update hook to config classes
paxtonfitzpatrick Dec 13, 2020
6cd9c5d
proofread files and cleaned up errors & style
paxtonfitzpatrick Dec 13, 2020
43ba787
added additional attribute update hooks
paxtonfitzpatrick Dec 13, 2020
8c6d92e
WIP Project and Job classes
paxtonfitzpatrick Dec 13, 2020
85808f6
added pattern validation helper for email address
paxtonfitzpatrick Dec 15, 2020
fc8a51d
lowercased PBS_params, will make uppercase for repr and str methods
paxtonfitzpatrick Dec 15, 2020
2dab96d
add options for data input & output dirs separately, remove option to…
paxtonfitzpatrick Dec 15, 2020
294ff24
option to notify on non-zero job return code, simplified option names
paxtonfitzpatrick Dec 16, 2020
2211fef
object initialization, config-tracking properties, WIP job creation &…
paxtonfitzpatrick Dec 16, 2020
f756361
added job_basename update hook
paxtonfitzpatrick Dec 16, 2020
7703d96
JobList wrapper class and functionality for parametrizing jobs
paxtonfitzpatrick Dec 16, 2020
a4b836b
renamed use_cluster_environ to slightly more intuitive name, use_glob…
paxtonfitzpatrick Dec 16, 2020
415461d
fixed logic in parse_config
paxtonfitzpatrick Dec 16, 2020
9af87d6
changed email address field to accept username, removed regex validation
paxtonfitzpatrick Dec 16, 2020
0b24118
renamed old submission script to start new one
paxtonfitzpatrick Dec 16, 2020
09615a6
renamed virtual environment activate/deactivate config fields
paxtonfitzpatrick Dec 16, 2020
6a1b5c3
lots of updates to Project class, script template creation, parameter…
paxtonfitzpatrick Dec 16, 2020
5a7c054
new exception subclass specific to issues with configuring jobs & job…
paxtonfitzpatrick Dec 16, 2020
d2dc28a
added & changed lots of fields in job script bash wrapper, stuck it i…
paxtonfitzpatrick Dec 16, 2020
11a4546
fixed circular imports due to type hinting throughout
paxtonfitzpatrick Dec 16, 2020
f94fa4a
clustertools has started working
paxtonfitzpatrick Dec 16, 2020
fa02d35
removed old submission and job scripts
paxtonfitzpatrick Jan 4, 2021
6babd44
various support machinery for job submission
paxtonfitzpatrick Jan 4, 2021
4689fc3
reorganized some modules
paxtonfitzpatrick Jan 4, 2021
2e6b3b6
added additional config options for email notifications
paxtonfitzpatrick Jan 4, 2021
65cad41
module for wrapper script object
paxtonfitzpatrick Jan 4, 2021
505ed12
implemented Job, JobList, JobListCache
paxtonfitzpatrick Jan 6, 2021
240d5b9
rename cmd_wrapper -> job_executable
paxtonfitzpatrick Jan 6, 2021
816f9a2
blank template for job monitoring script
paxtonfitzpatrick Jan 6, 2021
8f42612
added a few more notes
paxtonfitzpatrick Jan 6, 2021
cf43e7d
logic for setting #PBS -m key
paxtonfitzpatrick Jan 6, 2021
a92896b
big overhaul to composition scheme, access to job/script objects, div…
paxtonfitzpatrick Jan 6, 2021
3999eb1
add INFER option for queue field (per Discovery policy, >600-job batc…
paxtonfitzpatrick Jan 6, 2021
2127024
moved validation function to helpers
paxtonfitzpatrick Jan 8, 2021
1c66bfa
update name of email address field for clarity
paxtonfitzpatrick Jan 8, 2021
1195d62
check in WIP Job class before config-related class refactor
paxtonfitzpatrick Jan 8, 2021
744bbf7
allow top-level access to nested TrackedAttrConfig objects, add info …
paxtonfitzpatrick Jan 8, 2021
427e148
moved config-related modules to submodule
paxtonfitzpatrick Jan 9, 2021
ad47c72
added option to pass pre-update item validation hook to MonitoredEnvi…
paxtonfitzpatrick Jan 9, 2021
f21e36d
fixed a bug in TrackedAttrConfig.__getattr__
paxtonfitzpatrick Jan 9, 2021
ce0c393
added as_dict method and type hints
paxtonfitzpatrick Jan 9, 2021
fc64522
attribute update hooks now return the validated value to be set, whic…
paxtonfitzpatrick Jan 9, 2021
6369ad3
big typing class for @bindable decorator that may or may not be entir…
paxtonfitzpatrick Jan 9, 2021
c614b20
WIP config field update hooks
paxtonfitzpatrick Jan 9, 2021
e83b37d
updated mutating methods to call validate_item_hook on single item at…
paxtonfitzpatrick Jan 9, 2021
3e374d2
progress on config hooks, moving onto BaseConfig revamp now
paxtonfitzpatrick Jan 9, 2021
61b286d
reorganized config inheritence structure, wrote update hooks
paxtonfitzpatrick Jan 9, 2021
603e7ab
various import path changes from moving config modules, some typing c…
paxtonfitzpatrick Jan 9, 2021
88dd67f
Merge pull request #3 from paxtonfitzpatrick/config-refactor
paxtonfitzpatrick Jan 9, 2021
f8f64d0
removed job failure notification option since that appears to be brok…
paxtonfitzpatrick Jan 10, 2021
8d6e510
re-added options for notification on job failure -- should be able to…
paxtonfitzpatrick Jan 11, 2021
80420cc
saving WIP job.wrapper property to refactor project config access
paxtonfitzpatrick Jan 11, 2021
9902596
remove slew of Project properties and references to them, made config…
paxtonfitzpatrick Jan 11, 2021
720a7e4
Merge pull request #4 from paxtonfitzpatrick/refactor-project-config
paxtonfitzpatrick Jan 11, 2021
b505e16
add option for login vs non-login shell, speed up printenv command fo…
paxtonfitzpatrick Jan 12, 2021
e1956ee
renamed email field, renamed references to it
paxtonfitzpatrick Jan 12, 2021
878b517
much more efficient way to run is_file... not sure what I was doing b…
paxtonfitzpatrick Jan 12, 2021
5f92fe4
changed format of <DEFAULT> and <INFER> config fields to make it mor…
paxtonfitzpatrick Jan 12, 2021
85a8935
remvoed use_global_environ option and all references -- it was redund…
paxtonfitzpatrick Jan 12, 2021
bb04cbd
WIP wrapper property for Job object, TODO notes to save place
paxtonfitzpatrick Jan 12, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.idea/*
*.pyc
*.DS_Store
configs/
!*.gitkeep
notebooks/
cluster_tools.egg-info
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# include template files in source distribution
graft clustertools/templates
3 changes: 0 additions & 3 deletions cluster_scripts/collector.py

This file was deleted.

28 changes: 0 additions & 28 deletions cluster_scripts/config.ini

This file was deleted.

23 changes: 0 additions & 23 deletions cluster_scripts/config.py

This file was deleted.

3 changes: 0 additions & 3 deletions cluster_scripts/cruncher.py

This file was deleted.

42 changes: 42 additions & 0 deletions clustertools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from __future__ import annotations
from pathlib import Path


version_info = (0, 0, 1)
__version__ = '.'.join(map(str, version_info))

CLUSTERTOOLS_CONFIG_DIR = Path.home().joinpath('.clustertools')
CLUSTERTOOLS_TEMPLATES_DIR = Path(__file__).resolve().parent.joinpath('templates')


from clustertools.cluster import Cluster


# TODO: define __dir__ methods for classes to control IPython TAB-completion

# TODO: add logging functionality

# TODO: move all property setter docstrings to getters

# TODO: update type checking-related imports to conditionally import if
# typing.TYPE_CHECKING is True to avoid circular imports

# TODO: write global 'configure' function so global config params can be
# set via 'clustertools.configure'

# TODO: write global '_auto_detect_notebook' function that initializes
# variables that control output appearance/behavior based on whether
# clustertools was imported in a Jupyter Notebook

# TODO: decide whether to make numpy a requirement, optional requirement,
# tests_require (for static type checking only), or leave out altogether

# TODO: make project_config.notifications.user a list to support option
# for multiple users can be notified

# TODO(?): expose all options for #PBS -m directive for all job types
# rather than only offering most useful ones (project_config)

# TODO(?): move all type hint-related definitions to shared.typing so
# they can be imported conditionally to avoid polluting the namespace
# at runtime
229 changes: 229 additions & 0 deletions clustertools/cluster.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
from __future__ import annotations

import os
from pathlib import PurePosixPath
from typing import Optional, TYPE_CHECKING

from clustertools import CLUSTERTOOLS_CONFIG_DIR
from clustertools.file_objects.configs.global_config import GlobalConfig
from clustertools.project.project import Project
from clustertools.project.project_handler import ProjectHandlerMixin
from clustertools.shells.base_shell import BaseShell
from clustertools.shared.exceptions import ClusterToolsProjectError, SSHConnectionError

if TYPE_CHECKING:
from clustertools.shared.typing import NoneOrMore


# clustertools config directory structure
# $HOME
# └── .clustertools/
# ├── global_config.ini
# ├── project_name_1/
# │ └── .project_config.ini
# ├── project_name_2/
# │ └── .project_config.ini
# └── ...


class Cluster(BaseShell):
# ADD DOCSTRING
def __init__(
self,
hostname: str,
username: Optional[str] = None,
password: Optional[str] = None,
connect: bool = True,
**shell_kwargs
) -> None:
# ADD DOCSTRING
self.config = GlobalConfig(cluster=self)
cwd = shell_kwargs.pop('cwd', None)
if cwd is None and self.config.general.launch_in_project_dir:
cwd = self.config.general.project_dir
executable = shell_kwargs.pop('executable', self.config.general.executable)
env_additions = shell_kwargs.pop('env_additions', None)
port = shell_kwargs.pop('port', None)
super().__init__(hostname=hostname,
username=username,
password=password,
cwd=cwd,
executable=executable,
env_additions=env_additions,
port=port,
connect=False)
if connect and hostname != 'localhost':
self.connect(password=password, **shell_kwargs)
self.project = None
self._all_projects = tuple(next(os.walk(CLUSTERTOOLS_CONFIG_DIR))[1])


# TODO: define __eq__ and __isinstancecheck__ methods since dynamic
# retyping breaks type checks

##########################################################
# INITIALIZATION #
##########################################################
def connect(
self,
hostname: Optional[str] = None,
username: Optional[str] = None,
password: Optional[str] = None,
use_key: bool = False,
port: Optional[int] = None,
timeout: int = 60,
retries: int = 0,
retry_delay: int = 1
) -> None:
# ADD DOCSTRING
# TODO(?): after connecting, check all local project dirs exist
# on remote and are synced (checksums match)
super().connect(hostname=hostname,
username=username,
password=password,
use_key=use_key,
port=port,
timeout=timeout,
retries=retries,
retry_delay=retry_delay)
remote_home = PurePosixPath(self.getenv('HOME'))
self.config.remote_path = remote_home.joinpath('.clustertools/global_config.ini')

##########################################################
# PROJECT MANAGEMENT #
##########################################################
@property
def all_projects(self):
return self._all_projects

def _mixin_project(self):
# adds functionality that simplify interfacing with a Project
cls = self.__class__
cls_name = 'ClusterProjectHandler' # cls.__name__
cls_bases = (ProjectHandlerMixin, *cls.__bases__)
self.__class__ = type(cls_name, cls_bases, dict(cls.__dict__))

def _mixout_project(self):
# removes single Project-related functionality
self.__class__ = Cluster
# TODO: delattr the instance attributes

def create_project(self, name: str, **kwargs):
# ADD DOCSTRING - creates a new project configuration & an entry
# in $HOME/.clustertools
# TODO: should take all (or most) arguments in Project constructor
# TODO: would be possible to allow creating/partially loading
# projects before connecting, but would require a lot of
# additional coding around possible scenarios
if not self.connected:
raise SSHConnectionError("SSH connection must be open to create a project")
elif self.project is not None:
raise ClusterToolsProjectError(
"Cannot create a project when one is already loaded. Use "
"'cluster.unload_project()' to unload the current project "
"before creating a new one."
)
elif name in self.all_projects:
raise ClusterToolsProjectError(
f"Project '{name}' already exists. Use "
f"cluster.load_project('{name}') to load its previous state."
)
self.project = Project(name=name, cluster=self, **kwargs)
self._all_projects = tuple(list(self._all_projects) + [self.project.name])
self._mixin_project()

def load_project(self, name: str):
# ADD DOCSTRING
# loads a project form $HOME/.clustertools
if not self.connected:
raise SSHConnectionError("SSH connection must be open to load a project")
elif self.project is not None:
raise ClusterToolsProjectError(
f"Project '{self.project.name}' is already loaded. Use "
"'cluster.unload_project()' to unload the current project "
"before loading a new one"
)
self.project = Project.load(name=name, cluster=self)
self._mixin_project()

def delete_project(self, name: str, yes: Optional[bool] = None, force: bool = False):
# ADD DOCSTRING - note that:
# - manually setting 'yes' to either True or False overrides
# value of general.confirm_project_deletion in global config
# - passing 'force=True' is like passing 'yes=True' but ALSO
# will delete the project even if it's loaded and/or has
# running jobs (jobs will be stopped)
# TODO: write main body
# removes a project configuration in $HOME/.clustertools
# warns if not all jobs completed & prompts to confirm always
if force:
if yes is False:
raise ValueError("Cannot pass both 'yes=False' and 'force=True'")
else:
yes = True
elif yes is None:
yes = self.config.general.confirm_project_deletion
if self.project is not None and self.project.name == name:
if force:
self.unload_project()
else:
raise ClusterToolsProjectError(
f"Project '{self.project.name}' is currently loaded. Use "
"'cluster.unload_project()' to unload the project before "
"deleting (or pass 'force=True')"
)
# check if project has running jobs
# if project has running jobs
# if force
# stop all jobs (killthemall)
# else
# raise ClusterToolsProjectError
# if not yes:
# confirmed = prompt for y/n "are you sure ______"
# else:
# confirmed = True
# if confirmed:
# delete relevant files and directories
...
_projs = list(self._all_projects)
_projs.remove(name)
self._all_projects = tuple(_projs)

def unload_project(self, save_state: bool = True):
# ADD DOCSTRING - note that user should never set 'save_state'
# to False unless they're planning to delete the project
# immediately after unloading
# TODO: write me
# unloads the current project and "mixes out" the ProjectMixin
...
self._mixout_project()
pass

def status(self, projects: NoneOrMore[str] = None):
# ADD DOCSTRING
# TODO: write me
# displays status info for jobs associated with one,
# multiple, or [default] all projects
pass



##########################################################
# JOB SUBMISSION #
##########################################################
def submit(self, **kwargs):
pass

##########################################################
# JOB MONITORING #
##########################################################
def monitor(self):
pass

def killthemall(self):
# Hi @Tudor :)
pass

##########################################################
# JOB OUTPUT COLLECTION #
##########################################################
Empty file.
Empty file.
Loading