Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
256d585
remove checking for config file
donaldcampbelljr Jun 25, 2024
848f0ee
Merge branch 'refs/heads/dev' into dev_rename_args_455
donaldcampbelljr Jun 25, 2024
7a35c49
re-commit no longer checking for subcommand_args.config_file
donaldcampbelljr Jun 25, 2024
9c3d9e3
refactor --looper-config to --config
donaldcampbelljr Jun 25, 2024
d8437aa
remove --config-file in favor of using --pep-config
donaldcampbelljr Jun 25, 2024
a62ff35
work towards using consolidated piface, update generic schema
donaldcampbelljr Jun 27, 2024
168f012
pull updated hell_looper dev for #493
donaldcampbelljr Jun 27, 2024
2d2475b
fix pipeline_type for pipestat usage with consolidated pipelines, fix…
donaldcampbelljr Jun 27, 2024
eaab8f9
refactor looper init tutorial and add some color to terminal using rich
donaldcampbelljr Jun 28, 2024
db29fd9
lint
donaldcampbelljr Jun 28, 2024
acc02ab
add changes to init_piface, change colors for better contrast
donaldcampbelljr Jun 28, 2024
0ffb634
Update looper/cli_pydantic.py
donaldcampbelljr Jul 1, 2024
f63597c
Update looper/cli_pydantic.py
donaldcampbelljr Jul 1, 2024
a24e0e8
simplify selection options
donaldcampbelljr Jul 1, 2024
9d4551e
add docstrings
donaldcampbelljr Jul 1, 2024
cc1b1ad
fix looper config formatting on write
donaldcampbelljr Jul 1, 2024
636d10c
Merge pull request #508 from pepkit/dev_looper_init_walkthrough
donaldcampbelljr Jul 1, 2024
0a90e9a
add PipelineInterfaceConfigError
donaldcampbelljr Jul 1, 2024
923495d
Merge pull request #507 from pepkit/dev_consolidate_pifaces
donaldcampbelljr Jul 1, 2024
5ca885c
Merge pull request #505 from pepkit/dev_rename_args_455
donaldcampbelljr Jul 1, 2024
09c0665
update version and changelog
donaldcampbelljr Jul 1, 2024
c344f92
add ability to init generic piface during config if it does not exist
donaldcampbelljr Jul 3, 2024
487e833
add accepting multiple pifaces
donaldcampbelljr Jul 3, 2024
e5a8e7f
allow generating generic pifaces for many pifaces
donaldcampbelljr Jul 3, 2024
f64a4f0
update req peppy>=0.40.4
donaldcampbelljr Jul 18, 2024
a264e80
fix #512
donaldcampbelljr Aug 20, 2024
4c9549b
fix #511
donaldcampbelljr Aug 20, 2024
40c6634
add flag to looper init #514
donaldcampbelljr Aug 20, 2024
f3aa7bf
remove pause, fix registry path warning #514
donaldcampbelljr Aug 20, 2024
f5cd906
remove restarting looper_init, simply show output #514
donaldcampbelljr Aug 20, 2024
70dfb23
fix extra dash when writing .looper.yaml #514
donaldcampbelljr Aug 22, 2024
54682ae
add shortform argument for --package
donaldcampbelljr Aug 22, 2024
fdac0a8
make compute_packages a property and fix divvy inspect
donaldcampbelljr Aug 22, 2024
7d457a1
remove position based argument for divvy config, must use --config or…
donaldcampbelljr Aug 22, 2024
7966ec6
fix compute key value parsing under cli key in looper config
donaldcampbelljr Aug 22, 2024
907037e
allow compute section under cli key to be a single string for conveni…
donaldcampbelljr Aug 22, 2024
08af6cc
add exception messaging for phc login #516
donaldcampbelljr Aug 23, 2024
a01722f
Fix #518
donaldcampbelljr Aug 23, 2024
d9ea2ad
Add better warnings for missing looper config files #515
donaldcampbelljr Aug 23, 2024
b29494c
Add missing and malformed piface warning #515
donaldcampbelljr Aug 23, 2024
db8c228
add clarity if config file cannot be parsed #515
donaldcampbelljr Aug 23, 2024
3a9874e
allow calling pephub_path directly from pipestat namespace, version b…
donaldcampbelljr Aug 26, 2024
ffa812b
fix for #511
donaldcampbelljr Aug 27, 2024
68a1729
Revert "fix #511"
donaldcampbelljr Aug 27, 2024
d5fd36a
Revert "add exception messaging for phc login #516"
donaldcampbelljr Aug 27, 2024
d0cffcb
replace deprecated func
donaldcampbelljr Aug 27, 2024
165b183
Fix divvy, remove requirement for old package, ensure looper is using…
donaldcampbelljr Aug 28, 2024
f23f5aa
update peppy and eido requirements
donaldcampbelljr Sep 10, 2024
a7246de
update the looper init_piface output to no longer use var_templates
donaldcampbelljr Sep 19, 2024
c32c924
update changelog and version for 2.0.0a2 prerelease
donaldcampbelljr Sep 30, 2024
6a66d31
refactor tests for new hello_looper changes
donaldcampbelljr Sep 30, 2024
8796646
pull updated hello_looper readme
donaldcampbelljr Sep 30, 2024
8e48df9
Merge pull request #525 from pepkit/dev_refactor_tests_hello_looper
donaldcampbelljr Sep 30, 2024
b54e678
pull updated hello_looper output schema
donaldcampbelljr Oct 1, 2024
89cbfc2
pull updated hello_looper output schema (again)
donaldcampbelljr Oct 2, 2024
e0aaa04
use filepath (requires new yacman)
nsheff Oct 9, 2024
222abac
solve #537
donaldcampbelljr Dec 20, 2024
fed3fd3
solution for #536 and #522
donaldcampbelljr Dec 23, 2024
a7c5bd5
add ability to specify path for report and table commands #534
donaldcampbelljr Dec 30, 2024
0aa7309
Merge pull request #539 from pepkit/dev_cleanup_2.0
donaldcampbelljr Dec 30, 2024
47d0f29
update for pre-release 2.0.0a3
donaldcampbelljr Dec 30, 2024
a68b079
Merge branch 'master' into dev
donaldcampbelljr Jan 16, 2025
c0141f7
update changelog and versions for 2.0.0 release
donaldcampbelljr Jan 16, 2025
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
28 changes: 28 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,34 @@

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format.

## [2.0.0] -- 2025-01-16

This release breaks backwards compatibility for Looper versions < 2.0.0

### Fixed
- divvy init [#520](https://github.com/pepkit/looper/issues/520)
- replaced deprecated PEPHubClient function, `_load_raw_pep` with `.load_raw_pep`
- looper cli parameters now take priority as originally intended [#518](https://github.com/pepkit/looper/issues/518)
- fix divvy inspect
- remove printed dictionary at looper finish [#511](https://github.com/pepkit/looper/issues/511)
- fix [#536](https://github.com/pepkit/looper/issues/536)
- fix [#522](https://github.com/pepkit/looper/issues/522)
- fix [#537](https://github.com/pepkit/looper/issues/537)
- fix [#534](https://github.com/pepkit/looper/issues/534)

### Changed
- `--looper-config` is now `--config`, `-c`. [#455](https://github.com/pepkit/looper/issues/455)
- A pipeline interface now consolidates a `sample_interface` and a `project_interface` [#493](https://github.com/pepkit/looper/issues/493)
- Updated documentation for Looper 2.0.0, removing previous versions [pepspec PR #34](https://github.com/pepkit/pepspec/pull/34)
- remove position based argument for divvy config, must use --config or run as default config

### Added
- `looper init` tutorial [#466](https://github.com/pepkit/looper/issues/466)
- looper config allows for `pephub_path` in pipestat config section of `.looper.yaml` [#519](https://github.com/pepkit/looper/issues/519)
- improve error messaging for bad/malformed looper configurations [#515](https://github.com/pepkit/looper/issues/515)
- add shortform argument for --package (alias is now -p)


## [1.9.1] -- 2024-07-18

### Changed
Expand Down
4 changes: 2 additions & 2 deletions looper/_version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = "1.9.1"
# You must change the version in parser = pydantic2_argparse.ArgumentParser in cli_pydantic.py!!!
__version__ = "2.0.0"
# You must change the version in parser = pydantic_argparse.ArgumentParser in cli_pydantic.py!!!
16 changes: 10 additions & 6 deletions looper/cli_divvy.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ def add_subparser(cmd, description):

for sp in [sps["list"], sps["write"], sps["submit"], sps["inspect"]]:
sp.add_argument(
"config", nargs="?", default=None, help="Divvy configuration file."
"--config", nargs="?", default=None, help="Divvy configuration file."
)

sps["init"].add_argument("config", default=None, help="Divvy configuration file.")
sps["init"].add_argument("--config", default=None, help="Divvy configuration file.")

for sp in [sps["inspect"]]:
sp.add_argument(
Expand Down Expand Up @@ -124,9 +124,11 @@ def main():
sys.exit(0)

_LOGGER.debug("Divvy config: {}".format(args.config))

divcfg = select_divvy_config(args.config)

_LOGGER.info("Using divvy config: {}".format(divcfg))
dcc = ComputingConfiguration(filepath=divcfg)
dcc = ComputingConfiguration.from_yaml_file(filepath=divcfg)

if args.command == "list":
# Output header via logger and content via print so the user can
Expand All @@ -142,11 +144,13 @@ def main():
for pkg_name, pkg in dcc.compute_packages.items():
if pkg_name == args.package:
found = True
with open(pkg.submission_template, "r") as f:
with open(pkg["submission_template"], "r") as f:
print(f.read())
_LOGGER.info("Submission command is: " + pkg.submission_command + "\n")
_LOGGER.info(
"Submission command is: " + pkg["submission_command"] + "\n"
)
if pkg_name == "docker":
print("Docker args are: " + pkg.docker_args)
print("Docker args are: " + pkg["docker_args"])

if not found:
_LOGGER.info("Package not found. Use 'divvy list' to see list of packages.")
Expand Down
139 changes: 78 additions & 61 deletions looper/cli_pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
from pephubclient import PEPHubClient
from pydantic_argparse.argparse.parser import ArgumentParser

from divvy import select_divvy_config

from . import __version__

from .command_models.arguments import ArgumentEnum
Expand All @@ -54,9 +52,11 @@
read_yaml_file,
inspect_looper_config_file,
is_PEP_file_type,
looper_config_tutorial,
)

from typing import List, Tuple
from rich.console import Console


def opt_attr_pair(name: str) -> Tuple[str, str]:
Expand Down Expand Up @@ -122,52 +122,56 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
sys.exit(1)

if subcommand_name == "init":
return int(
not initiate_looper_config(
dotfile_path(),
subcommand_args.pep_config,
subcommand_args.output_dir,
subcommand_args.sample_pipeline_interfaces,
subcommand_args.project_pipeline_interfaces,
subcommand_args.force_yes,

console = Console()
console.clear()
console.rule(f"\n[magenta]Looper initialization[/magenta]")
selection = subcommand_args.generic
if selection is True:
console.clear()
return int(
not initiate_looper_config(
dotfile_path(),
subcommand_args.pep_config,
subcommand_args.output_dir,
subcommand_args.sample_pipeline_interfaces,
subcommand_args.project_pipeline_interfaces,
subcommand_args.force_yes,
)
)
)
else:
console.clear()
return int(looper_config_tutorial())

if subcommand_name == "init_piface":
sys.exit(int(not init_generic_pipeline()))

_LOGGER.info("Looper version: {}\nCommand: {}".format(__version__, subcommand_name))

if subcommand_args.config_file is None:
looper_cfg_path = os.path.relpath(dotfile_path(), start=os.curdir)
try:
if subcommand_args.looper_config:
looper_config_dict = read_looper_config_file(
subcommand_args.looper_config
)
looper_cfg_path = os.path.relpath(dotfile_path(), start=os.curdir)
try:
if subcommand_args.config:
looper_config_dict = read_looper_config_file(subcommand_args.config)
else:
looper_config_dict = read_looper_dotfile()
_LOGGER.info(f"Using looper config ({looper_cfg_path}).")

cli_modifiers_dict = None
for looper_config_key, looper_config_item in looper_config_dict.items():
if looper_config_key == CLI_KEY:
cli_modifiers_dict = looper_config_item
else:
looper_config_dict = read_looper_dotfile()
_LOGGER.info(f"Using looper config ({looper_cfg_path}).")

cli_modifiers_dict = None
for looper_config_key, looper_config_item in looper_config_dict.items():
if looper_config_key == CLI_KEY:
cli_modifiers_dict = looper_config_item
else:
setattr(subcommand_args, looper_config_key, looper_config_item)

except OSError:
parser.print_help(sys.stderr)
setattr(subcommand_args, looper_config_key, looper_config_item)

except OSError as e:
if subcommand_args.config:
_LOGGER.warning(
f"Looper config file does not exist. Use looper init to create one at {looper_cfg_path}."
f"\nLooper config file does not exist at given path {subcommand_args.config}. Use looper init to create one at {looper_cfg_path}."
)
sys.exit(1)
else:
_LOGGER.warning(
"This PEP configures looper through the project config. This approach is deprecated and will "
"be removed in future versions. Please use a looper config file. For more information see "
"looper.databio.org/en/latest/looper-config"
)
else:
_LOGGER.warning(e)

sys.exit(1)

subcommand_args = enrich_args_via_cfg(
subcommand_name,
Expand All @@ -191,12 +195,12 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
subcommand_args.ignore_flags = True

# Initialize project
if is_PEP_file_type(subcommand_args.config_file) and os.path.exists(
subcommand_args.config_file
if is_PEP_file_type(subcommand_args.pep_config) and os.path.exists(
subcommand_args.pep_config
):
try:
p = Project(
cfg=subcommand_args.config_file,
cfg=subcommand_args.pep_config,
amendments=subcommand_args.amend,
divcfg_path=divcfg,
runp=subcommand_name == "runp",
Expand All @@ -209,14 +213,14 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
except yaml.parser.ParserError as e:
_LOGGER.error(f"Project config parse failed -- {e}")
sys.exit(1)
elif is_pephub_registry_path(subcommand_args.config_file):
elif is_pephub_registry_path(subcommand_args.pep_config):
if vars(subcommand_args)[SAMPLE_PL_ARG]:
p = Project(
amendments=subcommand_args.amend,
divcfg_path=divcfg,
runp=subcommand_name == "runp",
project_dict=PEPHubClient()._load_raw_pep(
registry_path=subcommand_args.config_file
project_dict=PEPHubClient().load_raw_pep(
registry_path=subcommand_args.pep_config
),
**{
attr: getattr(subcommand_args, attr)
Expand Down Expand Up @@ -252,7 +256,7 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
# Check at the beginning if user wants to use pipestat and pipestat is configurable
is_pipestat_configured = (
prj._check_if_pipestat_configured(pipeline_type=PipelineLevel.PROJECT.value)
if getattr(subcommand_args, "project", None)
if getattr(subcommand_args, "project", None) or subcommand_name == "runp"
else prj._check_if_pipestat_configured()
)

Expand Down Expand Up @@ -330,13 +334,13 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None):
_LOGGER.warning("No looper configuration was supplied.")


def main(test_args=None) -> None:
def main(test_args=None) -> dict:
parser = pydantic_argparse.ArgumentParser(
model=TopLevelParser,
prog="looper",
description="Looper: A job submitter for Portable Encapsulated Projects",
add_help=True,
version="1.9.1",
version="2.0.0",
)

parser = add_short_arguments(parser, ArgumentEnum)
Expand All @@ -349,6 +353,10 @@ def main(test_args=None) -> None:
return run_looper(args, parser, test_args=test_args)


def main_cli() -> None:
main()


def _proc_resources_spec(args):
"""
Process CLI-sources compute setting specification. There are two sources
Expand All @@ -375,20 +383,29 @@ def _proc_resources_spec(args):
settings_data = {}
if not spec:
return settings_data
pairs = [(kv, kv.split("=")) for kv in spec]
bads = []
for orig, pair in pairs:
try:
k, v = pair
except ValueError:
bads.append(orig)
else:
settings_data[k] = v
if bads:
raise ValueError(
"Could not correctly parse itemized compute specification. "
"Correct format: " + EXAMPLE_COMPUTE_SPEC_FMT
)
if isinstance(
spec, str
): # compute: "partition=standard time='01-00:00:00' cores='32' mem='32000'"
spec = spec.split(sep=" ")
if isinstance(spec, list):
pairs = [(kv, kv.split("=")) for kv in spec]
bads = []
for orig, pair in pairs:
try:
k, v = pair
except ValueError:
bads.append(orig)
else:
settings_data[k] = v
if bads:
raise ValueError(
"Could not correctly parse itemized compute specification. "
"Correct format: " + EXAMPLE_COMPUTE_SPEC_FMT
)
elif isinstance(spec, dict):
for key, value in spec.items():
settings_data[key] = value

return settings_data


Expand Down
26 changes: 18 additions & 8 deletions looper/command_models/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,9 @@ class ArgumentEnum(enum.Enum):
default=(int, None),
description="Skip samples by numerical index",
)
CONFIG_FILE = Argument(
name="config_file",
default=(str, None),
description="Project configuration file",
)
LOOPER_CONFIG = Argument(
name="looper_config",
CONFIG = Argument(
name="config",
alias="-c",
default=(str, None),
description="Looper configuration file (YAML)",
)
Expand All @@ -188,6 +184,20 @@ class ArgumentEnum(enum.Enum):
default=(str, None),
description="Output directory",
)
REPORT_OUTPUT_DIR = Argument(
name="report_dir",
alias="-r",
default=(str, None),
description="Set location for looper report and looper table outputs",
)

GENERIC = Argument(
name="generic",
alias="-g",
default=(bool, False),
description="Use generic looper config?",
)

SAMPLE_PIPELINE_INTERFACES = Argument(
name="sample_pipeline_interfaces",
alias="-S",
Expand Down Expand Up @@ -232,12 +242,12 @@ class ArgumentEnum(enum.Enum):
)
PACKAGE = Argument(
name="package",
alias="-p",
default=(str, None),
description="Name of computing resource package to use",
)
COMPUTE = Argument(
name="compute",
alias="-c",
default=(List, []),
description="List of key-value pairs (k1=v1)",
)
Expand Down
9 changes: 6 additions & 3 deletions looper/command_models/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ def create_model(self) -> Type[pydantic.BaseModel]:
ArgumentEnum.SKIP.value,
ArgumentEnum.PEP_CONFIG.value,
ArgumentEnum.OUTPUT_DIR.value,
ArgumentEnum.CONFIG_FILE.value,
ArgumentEnum.LOOPER_CONFIG.value,
ArgumentEnum.CONFIG.value,
ArgumentEnum.SAMPLE_PIPELINE_INTERFACES.value,
ArgumentEnum.PROJECT_PIPELINE_INTERFACES.value,
ArgumentEnum.PIPESTAT.value,
Expand Down Expand Up @@ -125,7 +124,9 @@ def create_model(self) -> Type[pydantic.BaseModel]:
TableParser = Command(
"table",
MESSAGE_BY_SUBCOMMAND["table"],
[],
[
ArgumentEnum.REPORT_OUTPUT_DIR.value,
],
)


Expand All @@ -135,6 +136,7 @@ def create_model(self) -> Type[pydantic.BaseModel]:
MESSAGE_BY_SUBCOMMAND["report"],
[
ArgumentEnum.PORTABLE.value,
ArgumentEnum.REPORT_OUTPUT_DIR.value,
],
)

Expand Down Expand Up @@ -188,6 +190,7 @@ def create_model(self) -> Type[pydantic.BaseModel]:
ArgumentEnum.PEP_CONFIG.value,
ArgumentEnum.SAMPLE_PIPELINE_INTERFACES.value,
ArgumentEnum.PROJECT_PIPELINE_INTERFACES.value,
ArgumentEnum.GENERIC.value,
],
)

Expand Down
Loading
Loading