idmtools-cli 0.0.0.dev0__py3-none-any.whl → 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,113 @@
1
+ """Defines the init(templates) cli command."""
2
+ import itertools
3
+ import json
4
+ import logging
5
+ import os
6
+ import urllib.request
7
+ from logging import getLogger
8
+ from typing import Dict, List
9
+ from idmtools.config import IdmConfigParser
10
+ from idmtools.registry.plugin_specification import ProjectTemplate
11
+ from idmtools_cli.cli.entrypoint import cli
12
+
13
+ logger = getLogger(__name__)
14
+
15
+
16
+ @cli.group(help="Commands to help start or extend projects through templating.")
17
+ def init():
18
+ """Base init group command."""
19
+ pass
20
+
21
+
22
+ @cli.command(help="Export list of project templates.")
23
+ def init_export():
24
+ """Export project templates."""
25
+ with open('templates.json', 'w') as o:
26
+ import dataclasses
27
+ result = get_project_list()
28
+ result = {x: dataclasses.asdict(v) for x, v in result.items()}
29
+ json.dump(result, o)
30
+
31
+
32
+ def define_cookiecutter_project_command(project_details: ProjectTemplate):
33
+ """
34
+ Defines the specific project cookie cutter command.
35
+
36
+ Args:
37
+ project_details:
38
+
39
+ Returns:
40
+ Define a dynamic cookie cutter command around a template
41
+ """
42
+
43
+ @init.command(name=project_details.name, help=project_details.description)
44
+ def run_project():
45
+ from cookiecutter.main import cookiecutter
46
+ if not isinstance(project_details.url, list):
47
+ project_details.url = [project_details.url]
48
+ for url in project_details.url:
49
+ cookiecutter(url)
50
+
51
+ return run_project
52
+
53
+
54
+ def get_project_list() -> Dict[str, ProjectTemplate]:
55
+ """
56
+ Build a list of cookie cutter options for menu.
57
+
58
+ Returns:
59
+ Return list of project templates
60
+ """
61
+ from idmtools.registry.experiment_specification import ExperimentPlugins
62
+ from idmtools.registry.platform_specification import PlatformPlugins
63
+
64
+ # fetch
65
+ items = list()
66
+ f_dir = os.path.dirname(__file__)
67
+ with open(os.path.join(f_dir, 'common_project_templates.json'), 'rb') as fin:
68
+ items.extend(ProjectTemplate.read_templates_from_json_stream(fin))
69
+
70
+ for pm in [ExperimentPlugins().get_plugins(), PlatformPlugins().get_plugins()]:
71
+ items.extend(list(itertools.chain(*map(lambda pl: pl.get_project_templates(), pm))))
72
+
73
+ # check for values in config
74
+ url = IdmConfigParser.get_option('Templating', 'url')
75
+ if url:
76
+ logger.debug(f'Loading templates from url: {url}')
77
+ with urllib.request.urlopen(url) as s:
78
+ items.extend(ProjectTemplate.read_templates_from_json_stream(s))
79
+ result = {x.name: x for x in items}
80
+
81
+ if logger.isEnabledFor(logging.DEBUG):
82
+ logger.debug(f'Cookie cutter project list: {result}')
83
+
84
+ return result
85
+
86
+
87
+ def build_project_commands():
88
+ """
89
+ Builds the cookie cutter cli commands.
90
+
91
+ Returns:
92
+ None
93
+ """
94
+ result = get_project_list()
95
+ # Now define all the cookie cutter projects
96
+ for _name, details in result.items():
97
+ define_cookiecutter_project_command(details)
98
+
99
+
100
+ def read_templates_from_json_stream(items: List[ProjectTemplate], s):
101
+ """
102
+ Read Project Template from stream onto the list.
103
+
104
+ Args:
105
+ items: List to append data to
106
+ s: Stream where json data resides
107
+
108
+ Returns:
109
+ None
110
+ """
111
+ data = json.loads(s.read().decode())
112
+ for item in data:
113
+ items.append(ProjectTemplate(**item))
@@ -0,0 +1,106 @@
1
+ """Define our package group CLI command."""
2
+ import os
3
+ from logging import getLogger
4
+ import click
5
+ from typing import Optional, List
6
+ from idmtools_cli.cli.entrypoint import cli
7
+
8
+ user_logger = getLogger('user')
9
+
10
+
11
+ @cli.group(short_help="Contains commands related to package versions.")
12
+ def package():
13
+ """Package group cli command."""
14
+ pass
15
+
16
+
17
+ @package.command()
18
+ @click.option('--name', required=True, type=str, help="package name")
19
+ def latest_version(name: Optional[str]):
20
+ """
21
+ Display the latest version of a package.
22
+
23
+ Args:
24
+ name: package name
25
+ """
26
+ from idmtools_platform_comps.utils.package_version import get_latest_version
27
+ v = get_latest_version(name)
28
+ print(v)
29
+
30
+
31
+ @package.command()
32
+ @click.option('--name', required=True, type=str, help="package name")
33
+ @click.option('--base_version', required=True, default=None, type=str, help="package version")
34
+ def compatible_version(name: Optional[str], base_version: Optional[str]):
35
+ """
36
+ Display the latest compatible version of a package.
37
+
38
+ Args:
39
+ name: package name
40
+ base_version: package version
41
+ """
42
+ from idmtools_platform_comps.utils.package_version import get_latest_compatible_version
43
+ v = get_latest_compatible_version(name, base_version)
44
+ print(v)
45
+
46
+
47
+ @package.command()
48
+ @click.option('--name', required=True, type=str, help="package name")
49
+ @click.option('--all/--no-all', type=bool, default=False, help="package version")
50
+ def list_versions(name: Optional[str], all: Optional[bool]):
51
+ """
52
+ Display all package versions.
53
+
54
+ Args:
55
+ name: package name
56
+ all: True/False - return all or only released versions
57
+ """
58
+ from idmtools_platform_comps.utils.package_version import fetch_package_versions
59
+ versions = fetch_package_versions(name, not all)
60
+ print(versions)
61
+
62
+
63
+ @package.command()
64
+ @click.argument('requirement', type=click.Path(exists=True), required=False)
65
+ @click.option('--pkg', multiple=True, help="Package for override. Format: 'key==value'")
66
+ @click.option('--wheel', multiple=True, help="Local wheel file")
67
+ def updated_requirements(requirement: str = None, pkg: Optional[List[str]] = None, wheel: Optional[List[str]] = None):
68
+ """
69
+ Build Updated_Requirements from requirement file.
70
+
71
+ Args:
72
+ requirement: Path to requirement file
73
+ pkg: package name (along with version)
74
+ wheel: package wheel file
75
+ """
76
+ from idmtools_platform_comps.utils.python_requirements_ac.requirements_to_asset_collection import \
77
+ RequirementsToAssetCollection
78
+
79
+ pkg_list = list(pkg)
80
+ wheel_list = [os.path.abspath(w) for w in wheel]
81
+ pl = RequirementsToAssetCollection(None, requirements_path=requirement, pkg_list=pkg_list, local_wheels=wheel_list)
82
+ pl.save_updated_requirements()
83
+ req = open('requirements_updated.txt').read()
84
+ print(req)
85
+
86
+
87
+ @package.command()
88
+ @click.argument('requirement', type=click.Path(exists=True), required=False)
89
+ @click.option('--pkg', multiple=True, help="Package for override. Format: 'key==value'")
90
+ @click.option('--wheel', multiple=True, help="Local wheel file")
91
+ def checksum(requirement: str = None, pkg: Optional[List[str]] = None, wheel: Optional[List[str]] = None):
92
+ """
93
+ Construct checksum from requirement file.
94
+
95
+ Args:
96
+ requirement: path to requirement file
97
+ pkg: package name (along with version)
98
+ wheel: package wheel file
99
+ """
100
+ from idmtools_platform_comps.utils.python_requirements_ac.requirements_to_asset_collection import \
101
+ RequirementsToAssetCollection
102
+
103
+ pkg_list = list(pkg)
104
+ wheel_list = [os.path.abspath(w) for w in wheel]
105
+ pl = RequirementsToAssetCollection(None, requirements_path=requirement, pkg_list=pkg_list, local_wheels=wheel_list)
106
+ print(pl.checksum)
@@ -0,0 +1,158 @@
1
+ """
2
+ Defines the info group cli command and version command as well.
3
+ """
4
+ from collections import defaultdict
5
+
6
+ import os
7
+ from logging import getLogger, DEBUG
8
+ import stat
9
+ import click
10
+ import pyperclip
11
+
12
+ from idmtools.registry.master_plugin_registry import MasterPluginRegistry
13
+ from idmtools.registry.task_specification import TaskPlugins
14
+ from tabulate import tabulate
15
+ from idmtools.core.system_information import get_system_information
16
+ from idmtools.registry.platform_specification import PlatformPlugins
17
+ from idmtools_cli.cli.entrypoint import cli
18
+ from idmtools_cli.cli.utils import supported_platforms
19
+ from idmtools_cli.utils.cols import columns
20
+
21
+ logger = getLogger(__name__)
22
+
23
+
24
+ @cli.command(help="List version info about idmtools and plugins.")
25
+ @click.option('--no-plugins/--plugins', default=False, help="Control whether we display plugins with modules")
26
+ def version(no_plugins: bool):
27
+ """Returns version of all idmtools components."""
28
+ from idmtools import __version__
29
+ from idmtools_cli import __version__ as cli_version
30
+ plugin_map = MasterPluginRegistry().get_plugin_map()
31
+ module_map = defaultdict(dict)
32
+ for name in sorted(plugin_map.keys()):
33
+ try:
34
+ spec = plugin_map[name]
35
+ module_name = str(spec.get_type().__module__)
36
+ if module_name:
37
+ module_name = module_name.split(".")[0]
38
+ except Exception as e:
39
+ if logger.isEnabledFor(DEBUG):
40
+ logger.exception(e)
41
+ module_name = 'Unknown Module'
42
+ if plugin_map[name].get_version():
43
+ module_map[module_name][name] = plugin_map[name].get_version()
44
+
45
+ if not module_map['idmtools']:
46
+ module_map['idmtools'] = __version__
47
+
48
+ if not module_map['idmtools-cli']:
49
+ module_map['idmtools-cli'] = cli_version
50
+
51
+ for module in sorted(module_map.keys()):
52
+ if isinstance(module_map[module], dict):
53
+ mod_version = list(module_map[module].values())[0]
54
+ click.echo(click.style(columns((module.replace("_", "-"), 36), (f'Version: {mod_version}', 40)), fg='green'))
55
+ if not no_plugins:
56
+ click.echo(click.style(' Plugins:', fg='yellow'))
57
+ for plugin_name in sorted(module_map[module].keys()):
58
+ click.echo(click.style(columns(('', 3), (f'{plugin_name}', 25)), fg='blue'))
59
+ else:
60
+ click.echo(click.style(columns((module.replace("_", "-"), 36), (f'Version: {module_map[module]}', 40)), fg='green'))
61
+
62
+
63
+ @cli.group(help="Troubleshooting and debugging information.")
64
+ def info():
65
+ """Info cli subcommand."""
66
+ pass
67
+
68
+
69
+ @info.command(help="Provide an output with details about your current execution platform and IDM-Tools install")
70
+ @click.option('--copy-to-clipboard/--no-copy-to-clipboard', default=False, help="Copy output to clipboard")
71
+ @click.option('--no-format-for-gh/--format-for-gh', default=False, help="When copying to clipboard, do we want to "
72
+ "formatted for Github")
73
+ @click.option('--issue/--no-issue', default=False, help="Copy data and format for github alias")
74
+ @click.option('--output-filename', default=None, help="Output filename")
75
+ def system(copy_to_clipboard, no_format_for_gh, issue, output_filename):
76
+ """Provide info about your current install of idmtools."""
77
+ logger.debug("Building system info")
78
+ system_info = get_system_information()
79
+ logger.debug("Building system info output")
80
+ lines = [f'System Information\n{"=" * 20}']
81
+ ordered_fields = sorted(system_info.__dict__.keys())
82
+ [lines.append(f'{k}: {system_info.__dict__[k]}') for k in ordered_fields]
83
+ if os.name != 'nt':
84
+ logger.debug("Building windows info")
85
+ for f in ['workers', 'redis-data']:
86
+ fname = os.path.join(system_info.data_directory, f)
87
+ if os.path.exists(fname):
88
+ from pwd import getpwuid
89
+ s = os.stat(fname)
90
+ owned_by = f'{getpwuid(s.st_uid).pw_name} UID {s.st_uid}:{s.st_gid}'
91
+ lines.append(f'{fname} has permissions of {oct(stat.S_IMODE(os.lstat(fname).st_mode))} '
92
+ f'and is owned by {owned_by}')
93
+ logger.debug("Windows info done")
94
+ try:
95
+ import docker
96
+ logger.debug("Building docker info")
97
+ lines.append(f'\nDocker Information\n{"=" * 20}')
98
+ client = docker.from_env()
99
+ lines.append(f'Version: {client.version()}')
100
+ docker_info = client.info()
101
+ ordered_fields = sorted(docker_info.keys())
102
+ [lines.append(f'{k}: {docker_info[k]}') for k in ordered_fields]
103
+ logger.debug("docker info done")
104
+ except ImportError:
105
+ pass
106
+ except Exception as e:
107
+ logger.error(e)
108
+ raise e
109
+ if copy_to_clipboard:
110
+ logger.debug("Copying to clipboard")
111
+ output = '\n'.join(lines)
112
+ if not no_format_for_gh or issue:
113
+ logger.debug('Formatting for github')
114
+ # let's remove system information here by rebuilding without it
115
+ output = '\n'.join(lines[0:])
116
+ output = f'```### System Information\n{output}````'
117
+ pyperclip.copy(output)
118
+ if output_filename is not None:
119
+ with open(output_filename, 'w') as log_out:
120
+ log_out.writelines(lines)
121
+ else:
122
+ logger.debug("Writing output")
123
+ for line in lines:
124
+ click.echo(line)
125
+
126
+
127
+ @info.group(help="Commands to get information about installed IDM-Tools plugins")
128
+ def plugins():
129
+ """Info about plugins installed."""
130
+ pass
131
+
132
+
133
+ @plugins.command(help="List CLI plugins")
134
+ def cli():
135
+ """List CLI plugins."""
136
+ items = list(supported_platforms.keys())
137
+ print(tabulate([[x] for x in items], headers=['CLI Plugins'], tablefmt='psql'))
138
+
139
+
140
+ @plugins.command(help="List Platform plugins configuration aliases")
141
+ def platform_aliases():
142
+ """List platform aliases."""
143
+ aliases = PlatformPlugins().get_aliases()
144
+ print(tabulate([[name, details[1]] for name, details in aliases.items()], headers=['Platform Plugin Aliases', "Configuration Options"], tablefmt='psql'))
145
+
146
+
147
+ @plugins.command(help="List Platform plugins")
148
+ def platform():
149
+ """List platform plugins."""
150
+ platforms = PlatformPlugins().get_plugin_map().keys()
151
+ print(tabulate([[x] for x in platforms], headers=['Platform Plugins'], tablefmt='psql'))
152
+
153
+
154
+ @plugins.command(help="List Task plugins")
155
+ def task():
156
+ """List task plugins."""
157
+ tasks = TaskPlugins().get_plugin_map().keys()
158
+ print(tabulate([[x] for x in tasks], headers=['Task Plugins'], tablefmt='psql'))
@@ -0,0 +1,49 @@
1
+ """Defines utilities used with the cli commands."""
2
+ import sys
3
+ from typing import NoReturn, Union
4
+ import requests
5
+ from click import UsageError
6
+ from colorama import Fore
7
+ from idmtools.core.platform_factory import Platform
8
+ from idmtools_cli.iplatform_cli import PlatformCLIPlugins
9
+
10
+ supported_platforms = PlatformCLIPlugins().get_plugin_map()
11
+
12
+ tags_help = "Tag to filter by. This should be in the form name value. For example, if you have a tag type=PythonTask " \
13
+ "you would use --tags type PythonTask. In addition, you can provide multiple tags, ie --tags a 1 " \
14
+ "--tags b 2. This will perform an AND based query on the tags meaning only jobs contains ALL the tags " \
15
+ "specified will be displayed"
16
+
17
+
18
+ def show_error(message: Union[str, requests.Response]) -> NoReturn:
19
+ """
20
+ Display an error response from API on the command line.
21
+
22
+ Args:
23
+ message (Union[str, requests.Response]): message to display
24
+
25
+ Returns:
26
+ Nothing
27
+ """
28
+ print(f'{Fore.RED}Error{Fore.RESET}: {message}')
29
+ sys.exit(-1)
30
+
31
+
32
+ def get_platform_from_config_or_name(config_block, platform):
33
+ """
34
+ Attempt to find the config block or crete platform obj from name.
35
+
36
+ Args:
37
+ config_block: Config block
38
+ platform: Platform type
39
+
40
+ Returns:
41
+ Platform object
42
+ """
43
+ if platform is None and config_block is None:
44
+ raise UsageError("You must specify a platform or a configuration block")
45
+ if config_block:
46
+ platform_obj = Platform(config_block)
47
+ else:
48
+ platform_obj = supported_platforms[platform].get({})
49
+ return platform_obj
@@ -0,0 +1,141 @@
1
+ """Define our platform specific specifications.
2
+
3
+ This is a specific specification to illuminate a command CLI between platforms for interacting with
4
+ experiment/simulations.
5
+ """
6
+ #
7
+ from abc import ABC, abstractmethod
8
+ from typing import NoReturn, Dict, Set, cast, Optional, List, Tuple
9
+ import pluggy
10
+ from idmtools.registry.plugin_specification import PLUGIN_REFERENCE_NAME, PluginSpecification
11
+ from idmtools.registry.utils import load_plugin_map
12
+
13
+ get_platform_cli_spec = pluggy.HookspecMarker(PLUGIN_REFERENCE_NAME)
14
+ get_additional_commands_spec = pluggy.HookspecMarker(PLUGIN_REFERENCE_NAME)
15
+ get_platform_cli_impl = pluggy.HookimplMarker(PLUGIN_REFERENCE_NAME)
16
+ get_additional_commands_impl = pluggy.HookimplMarker(PLUGIN_REFERENCE_NAME)
17
+
18
+
19
+ class IPlatformCLI(ABC):
20
+ """The Base PLatformCLI definition. It is mostly abstract classes around fetching info from a platform."""
21
+
22
+ @abstractmethod
23
+ def get_experiment_status(self, id: Optional[str], tags: Optional[List[Tuple[str, str]]]) -> NoReturn:
24
+ """
25
+ Get experiment status from a platform.
26
+
27
+ Args:
28
+ id: Optional ID to search for
29
+ tags: Optional tags to filter for as well
30
+
31
+ Returns:
32
+ None
33
+ """
34
+ pass
35
+
36
+ @abstractmethod
37
+ def get_simulation_status(self, id: Optional[str], experiment_id: Optional[str], status: Optional[str],
38
+ tags: Optional[List[Tuple[str, str]]]) -> NoReturn:
39
+ """
40
+ Get simulation status.
41
+
42
+ Args:
43
+ id: Optional simulation id
44
+ experiment_id: Optional experiment id
45
+ status: Status to filter for
46
+ tags: Tags to filter for
47
+
48
+ Returns:
49
+ None
50
+ """
51
+ pass
52
+
53
+ @abstractmethod
54
+ def get_platform_information(self) -> dict:
55
+ """
56
+ Get any platform relevant information.
57
+
58
+ Returns:
59
+ Str containing platform info
60
+ """
61
+ pass
62
+
63
+
64
+ class PlatformCLISpecification(PluginSpecification, ABC):
65
+ """Defines the Platform CLI Plugin Base."""
66
+ @classmethod
67
+ def get_name(cls, strip_all: bool = True) -> str:
68
+ """
69
+ Get name of plugin. By default we remove the CLISpecification portion.
70
+
71
+ Args:
72
+ strip_all: When true, CLISpecification is stripped from name. When false only Specification is Stripped
73
+
74
+ Returns:
75
+ None
76
+ """
77
+ if strip_all:
78
+ ret = cls.__name__.replace("CLISpecification", '')
79
+ else:
80
+ ret = cls.__name__.replace('Specification', '')
81
+ return ret
82
+
83
+ @get_platform_cli_spec
84
+ def get(self, configuration: dict) -> IPlatformCLI:
85
+ """
86
+ Factor that should return a new platform using the passed-in configuration.
87
+
88
+ Args:
89
+ configuration:
90
+
91
+ Returns:
92
+ None
93
+
94
+ Raises:
95
+ NotImplementedError
96
+ """
97
+ raise NotImplementedError("Plugin did not implement get")
98
+
99
+ @get_additional_commands_spec
100
+ def get_additional_commands(self) -> NoReturn:
101
+ """
102
+ Get any additional commands defined by the platform CLI.
103
+
104
+ Returns:
105
+ None
106
+
107
+ Raises:
108
+ NotImplementedError
109
+ """
110
+ raise NotImplementedError("Plugin did not implement get_additional_commands")
111
+
112
+
113
+ class PlatformCLIPlugins:
114
+ """Platform CLI Plugin Manager. Loads all the plugins."""
115
+ def __init__(self, strip_all: bool = True) -> None:
116
+ """
117
+ Creates our plugin index.
118
+
119
+ Args:
120
+ strip_all: Formatting option for plugin names in registry
121
+ """
122
+ self._plugins = cast(Dict[str, PlatformCLISpecification],
123
+ load_plugin_map('idmtools_platform_cli', PlatformCLISpecification, strip_all))
124
+
125
+ def get_plugins(self) -> Set[PlatformCLISpecification]:
126
+ """
127
+ Get plugins in the manager.
128
+
129
+ Returns:
130
+ List of plugin specs
131
+ """
132
+ return set(self._plugins.values())
133
+
134
+ def get_plugin_map(self) -> Dict[str, PlatformCLISpecification]:
135
+ """
136
+ Get the plugin map.
137
+
138
+ Returns:
139
+ Plugin Dict with name of plugin -> plugin cli spec
140
+ """
141
+ return self._plugins
idmtools_cli/main.py ADDED
@@ -0,0 +1,52 @@
1
+ """Entrypoint for idmtools cli."""
2
+ import os
3
+ from typing import NoReturn
4
+ from colorama import init as color_init
5
+
6
+
7
+ def main() -> NoReturn:
8
+ """
9
+ This is our main run function for the CLI.
10
+
11
+ It basically calls start(load cli including the plugins) and then run the cli.
12
+
13
+ Returns:
14
+ None
15
+ """
16
+ os.environ['IDMTOOLS_NO_CONFIG_WARNING'] = '1'
17
+ from idmtools_cli.cli.entrypoint import cli
18
+ start()
19
+ cli(auto_envvar_prefix='IDMTOOLS_CLI')
20
+
21
+
22
+ def start() -> NoReturn:
23
+ """
24
+ Loads the different components of the CLI.
25
+
26
+ Currently this involves
27
+
28
+ 1) Initializing colorama
29
+ 2) Loading built-in commands
30
+ 3) Loading Platform CLI items
31
+ 4) Loading custom CLI from platform plugins
32
+
33
+ Returns:
34
+ None
35
+ """
36
+ from idmtools_cli.iplatform_cli import PlatformCLIPlugins
37
+ color_init()
38
+ import idmtools_cli.cli.init # noqa: F401
39
+ import idmtools_cli.cli.config_file # noqa: F401
40
+ import idmtools_cli.cli.system_info # noqa: F401
41
+ import idmtools_cli.cli.gitrepo # noqa: F401
42
+ import idmtools_cli.cli.package # noqa: F401
43
+ platform_plugins = PlatformCLIPlugins()
44
+ from idmtools_cli.cli.init import build_project_commands
45
+ build_project_commands()
46
+ # Trigger the loading of additional cli from platforms
47
+ [p.get_additional_commands() for p in platform_plugins.get_plugins()]
48
+
49
+
50
+ # our entrypoint for our cli
51
+ if __name__ == '__main__':
52
+ main()
@@ -0,0 +1 @@
1
+ """Module for cli utils."""