diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2a2081f..c6a88e3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,8 +11,7 @@ jobs: formatting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - + - uses: actions/checkout@v4 - name: Setup black linter run: conda create --quiet --name black black @@ -20,4 +19,5 @@ jobs: run: | export PATH="/usr/share/miniconda/bin:$PATH" source activate black + pip install black==23.3.0 black --check scif diff --git a/scif/__init__.py b/scif/__init__.py index 414b2fb..0458c35 100644 --- a/scif/__init__.py +++ b/scif/__init__.py @@ -1,13 +1 @@ -""" - -Copyright (C) 2017-2020 Vanessa Sochat. - -This Source Code Form is subject to the terms of the -Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed -with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -Modified from https://github.com/Visual-mov/Colorful-Julia (MIT License) - -""" - from scif.version import __version__ diff --git a/scif/client/__init__.py b/scif/client/__init__.py index fac2a23..e596557 100644 --- a/scif/client/__init__.py +++ b/scif/client/__init__.py @@ -2,7 +2,7 @@ """ -Copyright (C) 2016-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -167,8 +167,7 @@ def get_parser(): def get_subparsers(parser): - """get_subparser will get a dictionary of subparsers, to help with printing help - """ + """get_subparser will get a dictionary of subparsers, to help with printing help""" actions = [ action @@ -186,16 +185,16 @@ def get_subparsers(parser): def main(): - """main is the entrypoint to managing or interacting with an scif - organized filesystem. + """main is the entrypoint to managing or interacting with an scif + organized filesystem. """ parser = get_parser() subparsers = get_subparsers(parser) def help(return_code=0): - """print help, including the software version and active client - and exit with return code. + """print help, including the software version and active client + and exit with return code. """ version = scif.__version__ diff --git a/scif/client/dump.py b/scif/client/dump.py index 57131bb..d8d7a2e 100644 --- a/scif/client/dump.py +++ b/scif/client/dump.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -17,7 +17,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe client = ScifRecipe(quiet=True, writable=False) diff --git a/scif/client/execute.py b/scif/client/execute.py index 865948f..e5c0f1b 100644 --- a/scif/client/execute.py +++ b/scif/client/execute.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -17,7 +17,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe cmd = args.cmd diff --git a/scif/client/help.py b/scif/client/help.py index 385d2a0..af420eb 100644 --- a/scif/client/help.py +++ b/scif/client/help.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -17,7 +17,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe apps = args.app diff --git a/scif/client/inspect.py b/scif/client/inspect.py index cd7f053..9a3b7d4 100644 --- a/scif/client/inspect.py +++ b/scif/client/inspect.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -18,7 +18,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe # Inspect choices, r, e, l, a @@ -62,7 +61,6 @@ def main(args, parser, subparser): result = {} for app in apps: - inspection = client.inspect(app, attributes) if len(inspection) > 0: result[app] = inspection diff --git a/scif/client/install.py b/scif/client/install.py index d45bbfc..ca41b3f 100644 --- a/scif/client/install.py +++ b/scif/client/install.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -16,7 +16,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe apps = args.recipe diff --git a/scif/client/list.py b/scif/client/list.py index e759e85..7b1fdf1 100644 --- a/scif/client/list.py +++ b/scif/client/list.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -16,7 +16,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe client = ScifRecipe(writable=False, quiet=True) @@ -33,7 +32,6 @@ def main(args, parser, subparser): result.append(app.rjust(10)) if len(result) > 0: - if longlist is True: header = "[app] [root]" bot.custom(prefix="SCIF", message=header, color="CYAN") diff --git a/scif/client/preview.py b/scif/client/preview.py index 6a1b2b2..5625fab 100644 --- a/scif/client/preview.py +++ b/scif/client/preview.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -17,7 +17,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe apps = args.recipe diff --git a/scif/client/pyshell.py b/scif/client/pyshell.py index fc2e04c..27752d2 100644 --- a/scif/client/pyshell.py +++ b/scif/client/pyshell.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -17,7 +17,6 @@ def main(args, parser, subparser): - from scif.defaults import SCIF_SHELL as shell parsed = parse_input_preferences(args.recipe, quiet=args.quiet) @@ -54,8 +53,7 @@ def main(args, parser, subparser): def ipython(recipe, app=None, quiet=False, writable=True): - """embed the client with loaded recipe into an ipython session - """ + """embed the client with loaded recipe into an ipython session""" from scif.main import ScifRecipe from IPython import embed diff --git a/scif/client/run.py b/scif/client/run.py index 69433e7..7f0d1f0 100644 --- a/scif/client/run.py +++ b/scif/client/run.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2016-2020 Vanessa Sochat. +Copyright (C) 2016-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -16,7 +16,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe cmd = args.cmd diff --git a/scif/client/shell.py b/scif/client/shell.py index 9c214e3..1a0c89f 100644 --- a/scif/client/shell.py +++ b/scif/client/shell.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -18,7 +18,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe app = args.app diff --git a/scif/client/test.py b/scif/client/test.py index 6dbfd31..ecead19 100644 --- a/scif/client/test.py +++ b/scif/client/test.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2016-2020 Vanessa Sochat. +Copyright (C) 2016-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -16,7 +16,6 @@ def main(args, parser, subparser): - from scif.main import ScifRecipe cmd = args.cmd diff --git a/scif/client/utils.py b/scif/client/utils.py index 5b02092..8df6718 100644 --- a/scif/client/utils.py +++ b/scif/client/utils.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -21,11 +21,11 @@ def parse_input_preferences(recipe, quiet=False): """parse a recipe|app, meaning a list of one or more things that could be - any of the following: + any of the following: - Returns - ======= - parsed: a dictionary lookup with keys for app, recipe, and quiet. + Returns + ======= + parsed: a dictionary lookup with keys for app, recipe, and quiet. """ # if coming from inspect, will be string @@ -34,14 +34,12 @@ def parse_input_preferences(recipe, quiet=False): # First case: recipe and app if len(recipe) > 1: - app = recipe[1] recipe = recipe[0] quiet = True # Second case, no input or recipe|app else: - app = None # If no recipe provided, assume loading base diff --git a/scif/defaults.py b/scif/defaults.py index 5fe427a..a12b78d 100644 --- a/scif/defaults.py +++ b/scif/defaults.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -31,14 +31,14 @@ def convert2boolean(arg): def getenv(variable_key, default=None, required=False, silent=True): - """ getenv will attempt to get an environment variable. If the variable - is not found, None is returned. - - Paramters - ========= - variable_key: the variable name - required: exit with error if not found - silent: Do not print debugging information for variable + """getenv will attempt to get an environment variable. If the variable + is not found, None is returned. + + Paramters + ========= + variable_key: the variable name + required: exit with error if not found + silent: Do not print debugging information for variable """ variable = os.environ.get(variable_key, default) if variable is None and required: @@ -52,12 +52,12 @@ def getenv(variable_key, default=None, required=False, silent=True): def getenv_namespace(namespace="SCIF", func=None): """return all environment variables in a particular namespace, such as for - SCIF apps using a filter function (func). The function should take first - a key in the environment, and then the namespace variable. - If none provided, uses "starts with" equivalent. + SCIF apps using a filter function (func). The function should take first + a key in the environment, and then the namespace variable. + If none provided, uses "starts with" equivalent. - def func(key, namespace): - return key.startswith(namespace) + def func(key, namespace): + return key.startswith(namespace) """ if func is None: """does key start with namespace?""" diff --git a/scif/logger/message.py b/scif/logger/message.py index d046dc1..38123ed 100644 --- a/scif/logger/message.py +++ b/scif/logger/message.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -106,8 +106,7 @@ def emitOutput(self, level): return False def isEnabledFor(self, messageLevel): - """check if a messageLevel is enabled to emit a level - """ + """check if a messageLevel is enabled to emit a level""" if messageLevel <= self.level: return True return False @@ -262,8 +261,7 @@ def debug(self, message): self.emit(DEBUG, message, "DEBUG") def is_quiet(self): - """is_quiet returns true if the level is under 1 - """ + """is_quiet returns true if the level is under 1""" if self.level < 1: return False return True @@ -271,7 +269,7 @@ def is_quiet(self): # Terminal ------------------------------------------ def table(self, rows, col_width=2): - """table will print a table of entries. If the rows is + """table will print a table of entries. If the rows is a dictionary, the keys are interpreted as column names. if not, a numbered list is used. """ diff --git a/scif/logger/spinner.py b/scif/logger/spinner.py index 4b43aed..404b030 100644 --- a/scif/logger/spinner.py +++ b/scif/logger/spinner.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed diff --git a/scif/main/__init__.py b/scif/main/__init__.py index b95240d..4f41d41 100644 --- a/scif/main/__init__.py +++ b/scif/main/__init__.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed diff --git a/scif/main/apps.py b/scif/main/apps.py index 7d3b84c..a68c24c 100644 --- a/scif/main/apps.py +++ b/scif/main/apps.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -23,15 +23,14 @@ def app(self, app): Parameters ========== app: the name of the app to view - """ + """ if "apps" in self._config: if app in self._config["apps"]: return self._config["apps"][app] def apps(self): - """get a list of apps to show the user - """ + """get a list of apps to show the user""" apps = [] if self._config is not None: if "apps" in self._config: @@ -41,13 +40,13 @@ def apps(self): def activate(self, app, cmd=None, args=None): """if an app is valid, get it's environment to make it active. - Update the entrypoint to be relevant to the app runscript. - - Parameters - ========== - app: the name of the app to activate - cmd: if defined, the entry point (command) to run. Otherwise uses apprun - args: additional commands for the apprun + Update the entrypoint to be relevant to the app runscript. + + Parameters + ========== + app: the name of the app to activate + cmd: if defined, the entry point (command) to run. Otherwise uses apprun + args: additional commands for the apprun """ if app is None: @@ -107,9 +106,9 @@ def deactivate(self, app): def help(self, app): """print the help file for an app, if it exists. - Parameters - ========== - app: the app to export variables for + Parameters + ========== + app: the app to export variables for """ lines = None @@ -130,8 +129,8 @@ def help(self, app): def reset(self): """reset the SCIF filesystem, meaning that defaults are set, the entrypoint - if reset, and the environment is reset. Only maintain entry folder set - by environment, if it was defined. + if reset, and the environment is reset. Only maintain entry folder set + by environment, if it was defined. """ self.set_defaults() diff --git a/scif/main/base.py b/scif/main/base.py index 00e5551..c53ac71 100644 --- a/scif/main/base.py +++ b/scif/main/base.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -21,24 +21,24 @@ class ScifRecipe: """Create and work with a scif recipe. Usage typically looks like: - recipe = ScifRecipe('sregistry.scif') - - Parameters - ========== - path: the path to the scif recipe flie. + recipe = ScifRecipe('sregistry.scif') + + Parameters + ========== + path: the path to the scif recipe flie. """ def __init__(self, path=None, app=None, writable=True, quiet=False): """initialize the scientific filesystem by creating a scif folder - at the base, and loading the recipe to fill it. - - Parameters - ========== - path: is the first paramter, not required to initialize an empty - client session. The logic proceeds as follows: - 1. If path is not defined, we want (empty) interactive session - 2. We derive the base from the environment SCIF_BASE + at the base, and loading the recipe to fill it. + + Parameters + ========== + path: is the first paramter, not required to initialize an empty + client session. The logic proceeds as follows: + 1. If path is not defined, we want (empty) interactive session + 2. We derive the base from the environment SCIF_BASE """ # 0. base determined from environment @@ -53,7 +53,6 @@ def __init__(self, path=None, app=None, writable=True, quiet=False): # 1. Determine if path is a recipe or base if path is not None: - self.set_base(SCIF_BASE, writable=writable) # /scif self.load(path, app, quiet) # recipe, environment @@ -70,8 +69,7 @@ def __repr__(self): return "[scif]" def speak(self): - """the client should announce self given that the shell is being used. - """ + """the client should announce self given that the shell is being used.""" if self._base is not None: apps = " | ".join(self.apps()) bot.custom(prefix="%s %s" % (self, self._base), message=apps, color="CYAN") @@ -81,13 +79,13 @@ def speak(self): def load(self, path, app=None, quiet=False): """load a scif recipe into the object - Parameters - ========== - path: the complete path to the config (recipe file) to load, or - root path of filesystem (that from calling function defaults to - /scif) - app: if running with context of an active app, this will load the - active app environment for it as well. + Parameters + ========== + path: the complete path to the config (recipe file) to load, or + root path of filesystem (that from calling function defaults to + /scif) + app: if running with context of an active app, this will load the + active app environment for it as well. """ # 1. path is a recipe if os.path.isfile(path): diff --git a/scif/main/commands.py b/scif/main/commands.py index 9932bdd..739f725 100644 --- a/scif/main/commands.py +++ b/scif/main/commands.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -20,20 +20,20 @@ def _exec(self, app=None, interactive=False, exit=False): """exec is the underlying driver of both run and exec, taking a final - SCIF and executing the command for the user. + SCIF and executing the command for the user. - This function is called via self._exec, and the expectation is that - self.run or self.exec has been called first to prepare the environment - and SCIF settings. + This function is called via self._exec, and the expectation is that + self.run or self.exec has been called first to prepare the environment + and SCIF settings. - If a user wants to preserve an environment variable from the console - it can be referenced with [e], for example $SCIF_DATA --> [e]SCIF_DATA + If a user wants to preserve an environment variable from the console + it can be referenced with [e], for example $SCIF_DATA --> [e]SCIF_DATA - Parameters - ========== - app: the name of the application to execute a command to - interactive: if True, us os.system directly - exit: exit with return code from command (for test) + Parameters + ========== + app: the name of the application to execute a command to + interactive: if True, us os.system directly + exit: exit with return code from command (for test) """ @@ -79,7 +79,6 @@ def _exec(self, app=None, interactive=False, exit=False): # A shell will run the command if interactive is True: - # Will exit with error, if happens, otherwise exit with 0 if exit is True: result = self._run_command( @@ -197,7 +196,6 @@ def test(self, app=None, args=None): # Does the application have a test script? if app in self.apps(): - self.activate(app, args=args) if not self._set_entrypoint(app, "SCIF_APPTEST", args): diff --git a/scif/main/environment.py b/scif/main/environment.py index 05d5409..0c85393 100644 --- a/scif/main/environment.py +++ b/scif/main/environment.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -21,14 +21,14 @@ def append_path(self, varname, value): """append another directory to a path indexed by "varname" in the os.environ - these variables are typically not represented by the user in the appenv, - but are added dynamically by SCIF. Thus, they will appear in os.environ - groups that are added to self.environment at runtime. + these variables are typically not represented by the user in the appenv, + but are added dynamically by SCIF. Thus, they will appear in os.environ + groups that are added to self.environment at runtime. - Parameters - ========== - varname: the variable in the environment to append to (e.g., PATH) - value: the path to append (no :) + Parameters + ========== + varname: the variable in the environment to append to (e.g., PATH) + value: the path to append (no :) """ value = self._append_path(varname, value) @@ -38,17 +38,17 @@ def append_path(self, varname, value): def get_append_path(self, key, value, environ=None): """the driver function of append_path, with intention to return the correct - value and variable name for an environment of interest, this function - maps to _append_path e.g.: - - 1. if the variable is already defined, we append - 2. if the variable isn't defined, we set - - Parameters - ========== - key: the variable in the environment to append to (e.g., PATH) - value: the path to append (no :) - environment: the environment to look in. + value and variable name for an environment of interest, this function + maps to _append_path e.g.: + + 1. if the variable is already defined, we append + 2. if the variable isn't defined, we set + + Parameters + ========== + key: the variable in the environment to append to (e.g., PATH) + value: the path to append (no :) + environment: the environment to look in. """ from scif.defaults import SCIF_APPEND_PATHS, SCIF_ALLOW_APPEND @@ -62,41 +62,39 @@ def get_append_path(self, key, value, environ=None): def init_env(self, config, base="/scif", active=None): - """ env will parse the complete SCIF namespace environment from a config. - this will be defined for all apps to allow for easy interaction between - them, regardless of which individual app is active. - - Parameters - ========== - config: the config loaded in with "load" in this file. - active: the name of the active app, if relevant. - - Example: the following environment variables would be defined for an app - called "google-drive" Note that for the variable, the slash is - replaced with an underscore - - SCIF_APPDATA_google_drive=/scif/data/google-drive - SCIF_APPRUN_google_drive=/scif/apps/google-drive/scif/runscript - SCIF_APPHELP_google_drive=/scif/apps/google-drive/scif/runscript.help - SCIF_APPROOT_google_drive=/scif/apps/google-drive - SCIF_APPLIB_google_drive=/scif/apps/google-drive/lib - SCIF_APPMETA_google_drive=/scif/apps/google-drive/scif - SCIF_APPBIN_google_drive=/scif/apps/google-drive/bin - SCIF_APPENV_google_drive=/scif/apps/google-drive/scif/environment.sh - SCIF_APPLABELS_google_drive=/scif/apps/google-drive/scif/labels.json - - These paths and files are not created at this point, but just defined. + """env will parse the complete SCIF namespace environment from a config. + this will be defined for all apps to allow for easy interaction between + them, regardless of which individual app is active. + + Parameters + ========== + config: the config loaded in with "load" in this file. + active: the name of the active app, if relevant. + + Example: the following environment variables would be defined for an app + called "google-drive" Note that for the variable, the slash is + replaced with an underscore + + SCIF_APPDATA_google_drive=/scif/data/google-drive + SCIF_APPRUN_google_drive=/scif/apps/google-drive/scif/runscript + SCIF_APPHELP_google_drive=/scif/apps/google-drive/scif/runscript.help + SCIF_APPROOT_google_drive=/scif/apps/google-drive + SCIF_APPLIB_google_drive=/scif/apps/google-drive/lib + SCIF_APPMETA_google_drive=/scif/apps/google-drive/scif + SCIF_APPBIN_google_drive=/scif/apps/google-drive/bin + SCIF_APPENV_google_drive=/scif/apps/google-drive/scif/environment.sh + SCIF_APPLABELS_google_drive=/scif/apps/google-drive/scif/labels.json + + These paths and files are not created at this point, but just defined. """ envars = dict() if "apps" in config: - # Gloal SCIF variables for data and apps envars["SCIF_APPS"] = "%s/apps" % self._base envars["SCIF_DATA"] = "%s/data" % self._base for name, app in config["apps"].items(): - # Here we are adding variables for all apps. appenv = self.get_appenv_lookup(name) for varname, varval in appenv[name].items(): @@ -114,11 +112,11 @@ def init_env(self, config, base="/scif", active=None): def update_env(self, reset=False): - """ If the SCIF is loaded, upload the object's environment. + """If the SCIF is loaded, upload the object's environment. - Parameters - ========== - reset: if True, empty the environment before parsing from config + Parameters + ========== + reset: if True, empty the environment before parsing from config """ @@ -126,7 +124,6 @@ def update_env(self, reset=False): self.environment = dict() if self._config is not None: - # Update environment with app information updates = self._init_env(self._config, self._base) self.environment.update(updates) @@ -136,13 +133,13 @@ def update_env(self, reset=False): def mk_env(key, val, app=None): """a helper function to return a dictionary with a SCIF prefixed app name, - the key slashes replaced with underscores, and the value set. + the key slashes replaced with underscores, and the value set. - Parameters - ========== - app: the app name to define the variable for (not used if not defined) - key: the key (not including the SCIF_ prefix - val: the value to set + Parameters + ========== + app: the app name to define the variable for (not used if not defined) + key: the key (not including the SCIF_ prefix + val: the value to set """ key = "SCIF_%s" % key.upper() @@ -155,12 +152,12 @@ def mk_env(key, val, app=None): def load_env(self, app): """load an environment file for an app. We don't allow for manual entry - of any file, but limit to predetermined environment.sh file, if exists. - this function is inteded for runtime commands (shell or exec not install) + of any file, but limit to predetermined environment.sh file, if exists. + this function is inteded for runtime commands (shell or exec not install) - Parameters - ========== - app: the app to export variables for + Parameters + ========== + app: the app to export variables for """ updates = dict() @@ -176,7 +173,6 @@ def load_env(self, app): for line in lines: (key, _, val) = line.strip().partition("=") if val not in ["", None]: # skips export lines - updates[key] = val self.environment[key] = val return updates @@ -184,12 +180,12 @@ def load_env(self, app): def export_env(self, ps1=True): """export the current environment, and add the PS1 variable to indicate - the active shell display. This will start with values from the currently - active environment, and then add those from scif. + the active shell display. This will start with values from the currently + active environment, and then add those from scif. - Parameters - ========= - ps1: if True, change the shell prompt to scif> + Parameters + ========= + ps1: if True, change the shell prompt to scif> """ @@ -199,7 +195,6 @@ def export_env(self, ps1=True): runtime["PS1"] = "scif> " if hasattr(self, "environment"): - # Step 1. Do an update, allowing extension for PATHs for key, val in self.environment.items(): runtime[key] = self._append_path(key, val, self.environment) @@ -214,31 +209,31 @@ def export_env(self, ps1=True): def get_appenv(self, app, isolated=True, update=False): """return environment for a specific app, meaning the variables active - when it is running. - - Parameters - ========== - isolated: if True, only return the active app variables (example below) - update: also update the global self.environment. - - If isolated is True, don't include other apps. For - example, for an app `hello-world-echo` and isolated True, the following - is returned: - - { - 'SCIF_APPBIN': '/scif/apps/hello-world-echo/bin', - 'SCIF_APPDATA': '/scif/data/hello-world-echo', - 'SCIF_APPENV': '/scif/apps/hello-world-echo/scif/environment.sh', - 'SCIF_APPHELP': '/scif/apps/hello-world-echo/scif/runscript.help', - 'SCIF_APPLABELS': '/scif/apps/hello-world-echo/scif/labels.json', - 'SCIF_APPLIB': '/scif/apps/hello-world-echo/lib', - 'SCIF_APPMETA': '/scif/apps/hello-world-echo/scif', - 'SCIF_APPNAME': 'hello-world-echo', - 'SCIF_APPRECIPE': '/scif/apps/hello-world-echo/scif/hello-world-echo.scif', - 'SCIF_APPROOT': '/scif/apps/hello-world-echo', - 'SCIF_APPRUN': '/scif/apps/hello-world-echo/scif/runscript' - 'SCIF_APPTEST': '/scif/apps/hello-world-echo/scif/test.sh' - } + when it is running. + + Parameters + ========== + isolated: if True, only return the active app variables (example below) + update: also update the global self.environment. + + If isolated is True, don't include other apps. For + example, for an app `hello-world-echo` and isolated True, the following + is returned: + + { + 'SCIF_APPBIN': '/scif/apps/hello-world-echo/bin', + 'SCIF_APPDATA': '/scif/data/hello-world-echo', + 'SCIF_APPENV': '/scif/apps/hello-world-echo/scif/environment.sh', + 'SCIF_APPHELP': '/scif/apps/hello-world-echo/scif/runscript.help', + 'SCIF_APPLABELS': '/scif/apps/hello-world-echo/scif/labels.json', + 'SCIF_APPLIB': '/scif/apps/hello-world-echo/lib', + 'SCIF_APPMETA': '/scif/apps/hello-world-echo/scif', + 'SCIF_APPNAME': 'hello-world-echo', + 'SCIF_APPRECIPE': '/scif/apps/hello-world-echo/scif/hello-world-echo.scif', + 'SCIF_APPROOT': '/scif/apps/hello-world-echo', + 'SCIF_APPRUN': '/scif/apps/hello-world-echo/scif/runscript' + 'SCIF_APPTEST': '/scif/apps/hello-world-echo/scif/test.sh' + } """ final = dict() @@ -264,53 +259,52 @@ def get_appenv(self, app, isolated=True, update=False): def get_appenv_lookup(self, app): """create a dictionary with a highest level index the - app name, and underneath a generic lookup (without the app name) for - different variable types. - - Parameters - ========== - app: the new of the app to get the environment for - isolated: if True don't include other apps - - Eg, app with name "google-drive" would look like: - - - {'registry': { - 'appbin': '/scif/apps/registry/bin', - 'appdata': '/scif/data/registry', - 'appenv': '/scif/apps/registry/scif/environment.sh', - 'apphelp': '/scif/apps/registry/scif/runscript.help', - 'apptest': '/scif/apps/registry/scif/test.sh', - 'applabels': '/scif/apps/registry/scif/labels.json', - 'applib': '/scif/apps/registry/lib', - 'appmeta': '/scif/apps/registry/scif', - 'apprecipe': '/scif/apps/registry/scif/registry.scif' - 'approot': '/scif/apps/registry', - 'apprun': '/scif/apps/registry/scif/runscript' - } - } - - This function is intended to be shared by env above and the environment - generating functions in the main client, to have consistent behavior. - The above data structure gets parse into the (global) variables for - the particular app: - - {'SCIF_APPBIN_registry': '/scif/apps/registry/bin', - 'SCIF_APPDATA_registry': '/scif/data/registry', - 'SCIF_APPENV_registry': '/scif/apps/registry/scif/environment.sh', - 'SCIF_APPHELP_registry': '/scif/apps/registry/scif/runscript.help', - 'SCIF_APPLABELS_registry': '/scif/apps/registry/scif/labels.json', - 'SCIF_APPTEST_registry': '/scif/apps/registry/scif/test.sh', - 'SCIF_APPLIB_registry': '/scif/apps/registry/lib', - 'SCIF_APPMETA_registry': '/scif/apps/registry/scif', - 'SCIF_APPRECIPE_registry': '/scif/apps/registry/scif/registry.scif', - 'SCIF_APPROOT_registry': '/scif/apps/registry', - 'SCIF_APPRUN_registry': '/scif/apps/registry/scif/runscript'} + app name, and underneath a generic lookup (without the app name) for + different variable types. + + Parameters + ========== + app: the new of the app to get the environment for + isolated: if True don't include other apps + + Eg, app with name "google-drive" would look like: + + + {'registry': { + 'appbin': '/scif/apps/registry/bin', + 'appdata': '/scif/data/registry', + 'appenv': '/scif/apps/registry/scif/environment.sh', + 'apphelp': '/scif/apps/registry/scif/runscript.help', + 'apptest': '/scif/apps/registry/scif/test.sh', + 'applabels': '/scif/apps/registry/scif/labels.json', + 'applib': '/scif/apps/registry/lib', + 'appmeta': '/scif/apps/registry/scif', + 'apprecipe': '/scif/apps/registry/scif/registry.scif' + 'approot': '/scif/apps/registry', + 'apprun': '/scif/apps/registry/scif/runscript' + } + } + + This function is intended to be shared by env above and the environment + generating functions in the main client, to have consistent behavior. + The above data structure gets parse into the (global) variables for + the particular app: + + {'SCIF_APPBIN_registry': '/scif/apps/registry/bin', + 'SCIF_APPDATA_registry': '/scif/data/registry', + 'SCIF_APPENV_registry': '/scif/apps/registry/scif/environment.sh', + 'SCIF_APPHELP_registry': '/scif/apps/registry/scif/runscript.help', + 'SCIF_APPLABELS_registry': '/scif/apps/registry/scif/labels.json', + 'SCIF_APPTEST_registry': '/scif/apps/registry/scif/test.sh', + 'SCIF_APPLIB_registry': '/scif/apps/registry/lib', + 'SCIF_APPMETA_registry': '/scif/apps/registry/scif', + 'SCIF_APPRECIPE_registry': '/scif/apps/registry/scif/registry.scif', + 'SCIF_APPROOT_registry': '/scif/apps/registry', + 'SCIF_APPRUN_registry': '/scif/apps/registry/scif/runscript'} """ if app in self.apps(): - base = self._base envars = {app: {}} @@ -343,14 +337,14 @@ def get_appenv_lookup(self, app): def add_env(self, key, value): - """ add a key/value pair to the environment. Should begin with SCIF - to maintain proper namespace + """add a key/value pair to the environment. Should begin with SCIF + to maintain proper namespace - Parameters - ========== - key: the environment variable name. For SCIF, slashes should be - removed and replaced with underscore. - value: the value to set for the environment variable + Parameters + ========== + key: the environment variable name. For SCIF, slashes should be + removed and replaced with underscore. + value: the value to set for the environment variable """ if not hasattr(self, "environment"): @@ -371,8 +365,8 @@ def add_env(self, key, value): def get_env(self, key=None): """return a particular value for an environment variable, if the key - exists. If no keys are defined, the entire environment is returned. - For an app-specific environment, use get_appenv. + exists. If no keys are defined, the entire environment is returned. + For an app-specific environment, use get_appenv. """ if key is not None: if key in self.environment: diff --git a/scif/main/helpers.py b/scif/main/helpers.py index 5205922..fbd2144 100644 --- a/scif/main/helpers.py +++ b/scif/main/helpers.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2018-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -20,16 +20,16 @@ def get_parts(pair, default=None): """pair is expected to be a string with some key, value, and this function - will replace any "=" with a space, and then parse the remainder - for a first and second part (key and value pair). + will replace any "=" with a space, and then parse the remainder + for a first and second part (key and value pair). - We likely will need to use regular expressions for pairs that have - spaces or equals that need to be maintained. + We likely will need to use regular expressions for pairs that have + spaces or equals that need to be maintained. - Parameters - ========== - pair should be a single string, likely with a key and value split by - a space or equals sign. + Parameters + ========== + pair should be a single string, likely with a key and value split by + a space or equals sign. """ pair = pair.replace("=", " ") @@ -43,9 +43,9 @@ def get_parts(pair, default=None): def run_command(self, cmd, spinner=True, quiet=True): - """run_command will run a command (a list) and wrap in a spinner. A - result (dict) with message and return code is returned. If the - return value is not 0, an error is issed and we exit + """run_command will run a command (a list) and wrap in a spinner. A + result (dict) with message and return code is returned. If the + return value is not 0, an error is issed and we exit """ if spinner is True: bot.spinner.start() @@ -66,15 +66,15 @@ def run_command(self, cmd, spinner=True, quiet=True): def set_entrypoint(self, app, config_key="SCIF_APPRUN", args=None): """if the value is defined in the config and the file exists, set - the entrypoint for the app to execute the script. + the entrypoint for the app to execute the script. - Parameters - ========== - key: the entry in the config (a filename) to check for existence. If - it exists, then set it's execution using the default shell to - be the entrypoint. + Parameters + ========== + key: the entry in the config (a filename) to check for existence. If + it exists, then set it's execution using the default shell to + be the entrypoint. - returns True if the config entry and file are found, False otherwise + returns True if the config entry and file are found, False otherwise """ if app in self.apps(): @@ -92,12 +92,12 @@ def set_entrypoint(self, app, config_key="SCIF_APPRUN", args=None): def parse_entrypoint(entry_point=None): """parse entrypoint will return a list, where the first argument is the - executable, followed by arguments. This function also works to - parse arguments into a list. - - Parameters - ========== - entry_point: the entry point for the application, is + executable, followed by arguments. This function also works to + parse arguments into a list. + + Parameters + ========== + entry_point: the entry point for the application, is """ if entry_point is None: diff --git a/scif/main/install.py b/scif/main/install.py index 53fb837..311352a 100644 --- a/scif/main/install.py +++ b/scif/main/install.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -18,12 +18,12 @@ def install(self, app=None): """install recipes to a base. We assume this is the root of a system - or container, and will write the /scif directory on top of it. - If an app name is provided, install that app if it is found - in the config. This function goes through all steps to: + or container, and will write the /scif directory on top of it. + If an app name is provided, install that app if it is found + in the config. This function goes through all steps to: - 1. Install base folders to base, creating a folder for each app - 2. Install one or more apps to it, the config is already loaded + 1. Install base folders to base, creating a folder for each app + 2. Install one or more apps to it, the config is already loaded """ self._install_base() # Generate the folder structure @@ -31,8 +31,8 @@ def install(self, app=None): def init_app(self, app): - """initialize an app, meaning adding the metadata folder, bin, and - lib to it. The app is created at the base + """initialize an app, meaning adding the metadata folder, bin, and + lib to it. The app is created at the base """ settings = self.get_appenv_lookup(app)[app] @@ -44,7 +44,7 @@ def init_app(self, app): def install_apps(self, apps=None): """install one or more apps to the base. If app is defined, only - install app specified. Otherwise, install all found in config. + install app specified. Otherwise, install all found in config. """ if apps in [None, ""]: apps = self.apps() @@ -56,7 +56,6 @@ def install_apps(self, apps=None): bot.warning("No apps to install. Load a recipe or base with .load()") for app in apps: - # We must have the app defined in the config if app not in self._config["apps"]: bot.exit("Cannot find app %s in config." % app) @@ -88,11 +87,11 @@ def install_apps(self, apps=None): def install_labels(self, app, settings, config): """install labels will add labels to the app labelfile - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ lookup = dict() @@ -109,13 +108,13 @@ def install_labels(self, app, settings, config): def install_files(self, app, settings, config): """install files will add files (or directories) to a destination. - If none specified, they are placed in the app base + If none specified, they are placed in the app base - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ if "appfiles" in config: @@ -123,7 +122,6 @@ def install_files(self, app, settings, config): bot.info("+ " + "appfiles ".ljust(5) + app) for pair in files: - # Step 1: determine source and destination src, dest = get_parts(pair, default=settings["approot"]) @@ -142,15 +140,14 @@ def install_files(self, app, settings, config): def install_commands(self, app, settings, config): """install will finally, issue commands to install the app. - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ if "appinstall" in config: - # Change directory so the APP is $PWD pwd = os.getcwd() os.chdir(settings["approot"]) @@ -172,11 +169,11 @@ def install_commands(self, app, settings, config): def install_recipe(self, app, settings, config): """Write the initial recipe for the app to its metadata folder. - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ recipe_file = settings["apprecipe"] @@ -196,16 +193,16 @@ def install_recipe(self, app, settings, config): def install_script(self, section, app, settings, config, executable=False): """a general function used by install_runscript, install_help, and - install_environment to write a script to a file from a config setting - section + install_environment to write a script to a file from a config setting + section - Parameters - ========== - section: should be the name of the section in the config (e.g., apprun) - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) - executable: if the file is written, make it executable (defaults False) + Parameters + ========== + section: should be the name of the section in the config (e.g., apprun) + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) + executable: if the file is written, make it executable (defaults False) """ if section in config: @@ -220,27 +217,27 @@ def install_script(self, section, app, settings, config, executable=False): def install_runscript(self, app, settings, config, executable=True): """install runscript will prepare the runscript for an app. - the parameters are shared by _install_script + the parameters are shared by _install_script """ return self._install_script("apprun", app, settings, config, executable) def install_environment(self, app, settings, config): """install will run the content to export environment variables, if defined - the parameters are shared by _install_script + the parameters are shared by _install_script """ return self._install_script("appenv", app, settings, config) def install_help(self, app, settings, config): """install will write the help section, if defined. - the parameters are shared by _install_script + the parameters are shared by _install_script """ return self._install_script("apphelp", app, settings, config) def install_test(self, app, settings, config, executable=True): """install test will prepare a test script for an app. - the parameters are shared by _install_script + the parameters are shared by _install_script """ return self._install_script("apptest", app, settings, config, executable) diff --git a/scif/main/parser.py b/scif/main/parser.py index b38f48d..edaa6c5 100644 --- a/scif/main/parser.py +++ b/scif/main/parser.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -21,13 +21,13 @@ def load_filesystem(base, quiet=False): """load a filesystem based on a root path, which is usually /scif - Parameters - ========== - base: base to load. + Parameters + ========== + base: base to load. - Returns - ======= - config: a parsed recipe configuration for SCIF + Returns + ======= + config: a parsed recipe configuration for SCIF """ from scif.defaults import SCIF_APPS @@ -50,18 +50,17 @@ def load_filesystem(base, quiet=False): def load_recipe(path): """load will return a loaded in (user) scif configuration file - Parameters - ========== - path: a path to a scif recipe file + Parameters + ========== + path: a path to a scif recipe file - Returns - ======= - config: a parsed recipe configuration for SCIF + Returns + ======= + config: a parsed recipe configuration for SCIF """ path = os.path.abspath(path) if os.path.exists(path): - # Read in spec, skip empty lines, don't strip remaining spec = [ x.strip("\n") @@ -75,7 +74,6 @@ def load_recipe(path): name = None while len(spec) > 0: - # Clean up white trailing/leading space line = spec.pop(0) stripped = line.strip() @@ -86,7 +84,6 @@ def load_recipe(path): # A new section? elif stripped.startswith("%"): - # Remove any comments line = line.split("#", 1)[0].strip() @@ -114,29 +111,28 @@ def load_recipe(path): def finish_recipe(config, global_section="apps"): """ - finish recipe includes final steps to add to the runtime for an app. - Currently, this just means adding a command to source an environment - before running, if appenv is defined. The Python should handle putting - variables in the environment, however in some cases (if the variable - includes an environment variable: + finish recipe includes final steps to add to the runtime for an app. + Currently, this just means adding a command to source an environment + before running, if appenv is defined. The Python should handle putting + variables in the environment, however in some cases (if the variable + includes an environment variable: - VARIABLE1=$VARIABLE2 + VARIABLE1=$VARIABLE2 - It would not be properly sourced! So we add a source as the first - line of the runscript + It would not be properly sourced! So we add a source as the first + line of the runscript - Parameters - ========== - config: the configuation file produced by load_recipe. Assumed to have - a highest key of "apps" and then lookup by individual apps, - and then sections. Eg: config['apps']['myapp']['apprun'] + Parameters + ========== + config: the configuation file produced by load_recipe. Assumed to have + a highest key of "apps" and then lookup by individual apps, + and then sections. Eg: config['apps']['myapp']['apprun'] """ # The apps are the keys under global section "apps" apps = list(config[global_section].keys()) for app in apps: - # If an apprun is present and the system supports source, do it. if "appenv" in config[global_section][app]: appenv = config[global_section][app]["appenv"] @@ -154,12 +150,10 @@ def finish_recipe(config, global_section="apps"): def read_section(config, spec, section, name, global_section="apps"): - """read in a section to a list, and stop when we hit the next section - """ + """read in a section to a list, and stop when we hit the next section""" members = [] while True: - if len(spec) == 0: break next_line = spec[0] @@ -169,7 +163,6 @@ def read_section(config, spec, section, name, global_section="apps"): else: new_member = spec.pop(0) if not new_member.strip().startswith("#"): - # Strip whitespace for labels, files, environment if section in ["applabels", "appfiles", "appenv"]: new_member = new_member.strip() @@ -187,19 +180,19 @@ def read_section(config, spec, section, name, global_section="apps"): def add_section(config, section, name=None, global_section="apps"): - """ add section will add a section (and optionally) - section name to a config + """add section will add a section (and optionally) + section name to a config - Parameters - ========== - config: the config (dict) parsed thus far - section: the section type (e.g., appinstall) - name: an optional name, added as a level (e.g., google-drive) + Parameters + ========== + config: the config (dict) parsed thus far + section: the section type (e.g., appinstall) + name: an optional name, added as a level (e.g., google-drive) - Resulting data structure is: + Resulting data structure is: - config['registry']['apprun'] - config[name][section] + config['registry']['apprun'] + config[name][section] """ diff --git a/scif/main/preview.py b/scif/main/preview.py index 920cedc..71cf39f 100644 --- a/scif/main/preview.py +++ b/scif/main/preview.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -18,19 +18,19 @@ def preview(self, apps=None): - """preview the complete setup for a scientific filesytem. This is useful - to print out actions for install (without doing them). + """preview the complete setup for a scientific filesytem. This is useful + to print out actions for install (without doing them). """ self._preview_base() # preview the folder structure self._preview_apps(apps) # App install def preview_base(self): - """ preview basic scif structure at the base for apps and metadata + """preview basic scif structure at the base for apps and metadata - Parameters - ========== - base: the full path to the root folder to create /scif + Parameters + ========== + base: the full path to the root folder to create /scif """ if not hasattr(self, "_base"): bot.exit("Please set the base before preview.") @@ -42,7 +42,7 @@ def preview_base(self): def preview_apps(self, apps=None): """install one or more apps to the base. If app is defined, only - install app specified. Otherwise, install all found in config. + install app specified. Otherwise, install all found in config. """ if apps in [None, []]: apps = self.apps() @@ -51,7 +51,6 @@ def preview_apps(self, apps=None): apps = [apps] for app in apps: - # We must have the app defined in the config if app not in self._config["apps"]: bot.exit("Cannot find app %s in config." % app) @@ -75,8 +74,8 @@ def preview_apps(self, apps=None): def init_app_preview(self, app): - """initialize an app, meaning adding the metadata folder, bin, and - lib to it. The app is created at the base + """initialize an app, meaning adding the metadata folder, bin, and + lib to it. The app is created at the base """ settings = self.get_appenv_lookup(app)[app] @@ -89,12 +88,12 @@ def init_app_preview(self, app): def preview_runscript(self, app, settings, config): """preview the runscript for an app - - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ if "apprun" in config: @@ -108,11 +107,11 @@ def preview_runscript(self, app, settings, config): def preview_test(self, app, settings, config): """preview the test for the app - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ if "apptest" in config: @@ -125,11 +124,11 @@ def preview_test(self, app, settings, config): def preview_labels(self, app, settings, config): """preview labels for an app - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ lookup = "" @@ -146,13 +145,13 @@ def preview_labels(self, app, settings, config): def preview_files(self, app, settings, config): """install files will add files (or directories) to a destination. - If none specified, they are placed in the app base + If none specified, they are placed in the app base - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ @@ -161,7 +160,6 @@ def preview_files(self, app, settings, config): bot.info("+ " + "appfiles ".ljust(5) + app) for pair in files: - # Step 1: determine source and destination src, dest = get_parts(pair, default=settings["approot"]) print("%s --> %s \n" % (src, dest)) @@ -170,11 +168,11 @@ def preview_files(self, app, settings, config): def preview_commands(self, app, settings, config): """install will finally, issue commands to install the app. - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ cmd = "" @@ -188,11 +186,11 @@ def preview_commands(self, app, settings, config): def preview_recipe(self, app, settings, config): """Write the initial recipe for the app to its metadata folder. - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars - config: should be the config for the app obtained with self.app(app) + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars + config: should be the config for the app obtained with self.app(app) """ recipe_file = settings["apprecipe"] @@ -212,10 +210,10 @@ def preview_recipe(self, app, settings, config): def preview_environment(self, app, settings, config): """preview the environment section - Parameters - ========== - app should be the name of the app, for lookup in config['apps'] - settings: the output of _init_app(), a dictionary of environment vars + Parameters + ========== + app should be the name of the app, for lookup in config['apps'] + settings: the output of _init_app(), a dictionary of environment vars """ content = "" diff --git a/scif/main/setup.py b/scif/main/setup.py index d913baa..e54442c 100644 --- a/scif/main/setup.py +++ b/scif/main/setup.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -17,12 +17,12 @@ def set_base(self, base="/", writable=True): - """ set the base (the root where to create /scif) and determine if - it is writable + """set the base (the root where to create /scif) and determine if + it is writable - Parameters - ========== - base: the full path to the root folder to create /scif + Parameters + ========== + base: the full path to the root folder to create /scif """ # The user is likely to give path to scif (should still work) base = base.strip("scif") @@ -46,9 +46,9 @@ def set_base(self, base="/", writable=True): def set_defaults(self, entry_point=None): - """set the defaults for the SCIF state at start up. - Usually this means parsing them from the environment. We hold these - with the object so we can easily maintain and change state. + """set the defaults for the SCIF state at start up. + Usually this means parsing them from the environment. We hold these + with the object so we can easily maintain and change state. """ # The entrypoint is the runscript (or /bin/bash default) @@ -64,11 +64,11 @@ def set_defaults(self, entry_point=None): def install_base(self): - """ create basic scif structure at the base for apps and metadata + """create basic scif structure at the base for apps and metadata - Parameters - ========== - base: the full path to the root folder to create /scif + Parameters + ========== + base: the full path to the root folder to create /scif """ if not hasattr(self, "_base"): bot.exit("Please set the base before installing to it.") diff --git a/scif/tests/test_utils.py b/scif/tests/test_utils.py index e985d73..d71ac38 100755 --- a/scif/tests/test_utils.py +++ b/scif/tests/test_utils.py @@ -2,7 +2,7 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -31,8 +31,7 @@ def tearDown(self): shutil.rmtree(self.tmpdir) def test_write_read_files(self): - """test_write_read_files will test the functions write_file and read_file - """ + """test_write_read_files will test the functions write_file and read_file""" print("Testing utils.write_file...") from scif.utils import write_file @@ -68,8 +67,7 @@ def test_write_read_files(self): self.assertTrue("Wakkawakkawakka" in content) def test_run_command(self): - """test running a command - """ + """test running a command""" print("Testing utils.run_command") from scif.utils import run_command diff --git a/scif/utils/fileio.py b/scif/utils/fileio.py index 44b21ce..94efdd0 100644 --- a/scif/utils/fileio.py +++ b/scif/utils/fileio.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -40,11 +40,11 @@ def mkdir_p(path): def which(software): """which is a substitute for shutil.which, which is only supported in - python 3 - - Parameters - ========== - software: the name of the executable to find + python 3 + + Parameters + ========== + software: the name of the executable to find """ path = os.getenv("PATH") @@ -62,9 +62,9 @@ def which(software): def make_executable(filename): """make a file executable by doing the equivalent of chmod+x - Parameters - ========== - filename: the name of the file to make executable + Parameters + ========== + filename: the name of the file to make executable """ if os.path.exists(filename): st = os.stat(filename) @@ -73,8 +73,7 @@ def make_executable(filename): def copyfile(source, destination, force=True): - """copy a file from a source to its destination. - """ + """copy a file from a source to its destination.""" if os.path.exists(destination) and force is True: os.remove(destination) shutil.copyfile(source, destination) @@ -83,7 +82,7 @@ def copyfile(source, destination, force=True): def write_file(filename, content, mode="w"): """write_file will open a file, "filename" and write content, "content" - and properly close the file + and properly close the file """ with codecs.open(filename, mode, encoding="utf-8") as filey: filey.writelines(content) @@ -93,11 +92,11 @@ def write_file(filename, content, mode="w"): def write_json(json_obj, filename, mode="w", print_pretty=True): """write_json will (optionally,pretty print) a json object to file - Parameters - ========== - json_obj: the dict to print to json - filename: the output file to write to - pretty_print: if True, will use nicer formatting + Parameters + ========== + json_obj: the dict to print to json + filename: the output file to write to + pretty_print: if True, will use nicer formatting """ with codecs.open(filename, mode, encoding="utf-8") as filey: if print_pretty: @@ -109,7 +108,7 @@ def write_json(json_obj, filename, mode="w", print_pretty=True): def read_file(filename, mode="r", readlines=True): """write_file will open a file, "filename" and write content, "content" - and properly close the file + and properly close the file """ with codecs.open(filename, mode, encoding="utf-8") as filey: if readlines is True: @@ -121,7 +120,7 @@ def read_file(filename, mode="r", readlines=True): def read_json(filename, mode="r"): """read_json reads in a json file and returns - the data structure as dict. + the data structure as dict. """ with codecs.open(filename, mode, encoding="utf-8") as filey: data = json.load(filey) diff --git a/scif/utils/terminal.py b/scif/utils/terminal.py index a972d7c..2a6ee1e 100644 --- a/scif/utils/terminal.py +++ b/scif/utils/terminal.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed @@ -24,19 +24,18 @@ def get_installdir(): - """get_installdir returns the installation directory of the application - """ + """get_installdir returns the installation directory of the application""" return os.path.abspath(os.path.dirname(os.path.dirname(__file__))) def run_command(cmd, sudo=False, quiet=False): """run_command uses subprocess to send a command to the terminal. - Parameters - ========== - cmd: the command to send, should be a list for subprocess - sudo: if True (default False) command will be run asking for sudo - quiet: skip printing output to the terminal + Parameters + ========== + cmd: the command to send, should be a list for subprocess + sudo: if True (default False) command will be run asking for sudo + quiet: skip printing output to the terminal """ if not isinstance(cmd, list): cmd = shlex.split(cmd) diff --git a/scif/version.py b/scif/version.py index 4da0ced..088a3fb 100644 --- a/scif/version.py +++ b/scif/version.py @@ -1,6 +1,6 @@ """ -Copyright (C) 2017-2020 Vanessa Sochat. +Copyright (C) 2017-2024 Vanessa Sochat. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed diff --git a/setup.py b/setup.py index 59989a1..b166eb4 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ def get_lookup(): - """get version by way of scif.version, returns a + """get version by way of scif.version, returns a lookup dictionary with several global variables without needing to import singularity """ @@ -65,7 +65,6 @@ def get_requirements(lookup=None, key="INSTALL_REQUIRES"): if __name__ == "__main__": - INSTALL_REQUIRES = get_requirements(lookup) INSTALL_REQUIRES_ALL = get_requirements(lookup, "INSTALL_REQUIRES_ALL")