ae-shell 0.3.7__tar.gz → 0.3.8__tar.gz
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.
- {ae_shell-0.3.7 → ae_shell-0.3.8}/LICENSE.md +1 -1
- {ae_shell-0.3.7/ae_shell.egg-info → ae_shell-0.3.8}/PKG-INFO +5 -5
- {ae_shell-0.3.7 → ae_shell-0.3.8}/README.md +3 -3
- ae_shell-0.3.8/ae/shell.py +253 -0
- {ae_shell-0.3.7 → ae_shell-0.3.8/ae_shell.egg-info}/PKG-INFO +5 -5
- {ae_shell-0.3.7 → ae_shell-0.3.8}/pyproject.toml +1 -1
- {ae_shell-0.3.7 → ae_shell-0.3.8}/setup.py +6 -6
- ae_shell-0.3.8/tests/test_shell.py +348 -0
- ae_shell-0.3.7/ae/shell.py +0 -1460
- ae_shell-0.3.7/tests/test_shell.py +0 -2017
- {ae_shell-0.3.7 → ae_shell-0.3.8}/ae_shell.egg-info/SOURCES.txt +0 -0
- {ae_shell-0.3.7 → ae_shell-0.3.8}/ae_shell.egg-info/dependency_links.txt +0 -0
- {ae_shell-0.3.7 → ae_shell-0.3.8}/ae_shell.egg-info/requires.txt +0 -0
- {ae_shell-0.3.7 → ae_shell-0.3.8}/ae_shell.egg-info/top_level.txt +0 -0
- {ae_shell-0.3.7 → ae_shell-0.3.8}/ae_shell.egg-info/zip-safe +0 -0
- {ae_shell-0.3.7 → ae_shell-0.3.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ae_shell
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: ae namespace module portion shell: shell execution and environment helpers
|
|
5
5
|
Home-page: https://gitlab.com/ae-group/ae_shell
|
|
6
6
|
Author: AndiEcker
|
|
@@ -16,7 +16,7 @@ Classifier: Natural Language :: English
|
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Requires-Python: >=3.9
|
|
@@ -65,13 +65,13 @@ Dynamic: summary
|
|
|
65
65
|
|
|
66
66
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.101 -->
|
|
67
67
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.22 -->
|
|
68
|
-
# shell 0.3.
|
|
68
|
+
# shell 0.3.8
|
|
69
69
|
|
|
70
70
|
[](
|
|
71
71
|
https://gitlab.com/ae-group/ae_shell)
|
|
72
72
|
[](
|
|
74
|
+
https://gitlab.com/ae-group/ae_shell/-/tree/release0.3.8)
|
|
75
75
|
[](
|
|
76
76
|
https://pypi.org/project/ae-shell/#history)
|
|
77
77
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.101 -->
|
|
2
2
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.22 -->
|
|
3
|
-
# shell 0.3.
|
|
3
|
+
# shell 0.3.8
|
|
4
4
|
|
|
5
5
|
[](
|
|
6
6
|
https://gitlab.com/ae-group/ae_shell)
|
|
7
7
|
[](
|
|
9
|
+
https://gitlab.com/ae-group/ae_shell/-/tree/release0.3.8)
|
|
10
10
|
[](
|
|
11
11
|
https://pypi.org/project/ae-shell/#history)
|
|
12
12
|
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""
|
|
2
|
+
shell execution and environment helpers
|
|
3
|
+
=======================================
|
|
4
|
+
|
|
5
|
+
.. hint::
|
|
6
|
+
this module is designed to provide a comprehensive set of constants and helper functions
|
|
7
|
+
for executing and managing external shell commands.
|
|
8
|
+
|
|
9
|
+
- :func:`debug_or_verbose`: checks if the application is running in debug or verbose mode.
|
|
10
|
+
- :func:`get_domain_user_var`: retrieves an OS environment variable value for a specific domain and/or user.
|
|
11
|
+
- :func:`hint`: provides a hint message based on the provided arguments.
|
|
12
|
+
- :func:`in_os_env`: context manager to temporarily add environment variables from the dotenv files that not exist
|
|
13
|
+
in os.environ to it.
|
|
14
|
+
- :func:`mask_token`: hide/mask tokens in a text block, to prevent to show them in logs or error messages.
|
|
15
|
+
- :func:`sh_exec`: generic/fundamental function for all other shell execution helpers.
|
|
16
|
+
- :func:`sh_exit_if_exec_err`: extended version of :func:`sh_exec` with automatically checks for errors
|
|
17
|
+
after a command is executed and handles application termination gracefully.
|
|
18
|
+
|
|
19
|
+
- :data:`STDERR_BEG_MARKER`: marker used in the console output for the beginning of stderr output.
|
|
20
|
+
- :data:`STDERR_END_MARKER`: marker used in the console output for the end of stderr output.
|
|
21
|
+
"""
|
|
22
|
+
import os
|
|
23
|
+
import shlex
|
|
24
|
+
import subprocess
|
|
25
|
+
|
|
26
|
+
from contextlib import contextmanager
|
|
27
|
+
from typing import Any, Callable, Iterable, Iterator, MutableMapping, Optional, Union, cast, overload
|
|
28
|
+
|
|
29
|
+
from ae.base import UNSET, dummy_function, env_str, load_env_var_defaults, norm_name # type: ignore
|
|
30
|
+
from ae.core import main_app_instance, AppBase # type: ignore
|
|
31
|
+
from ae.console import MAIN_SECTION_NAME, ConsoleApp # type: ignore
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__version__ = '0.3.8'
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
STDERR_BEG_MARKER = "vvv STDERR vvv" #: :paramref:`ae.shell.sh_exec.lines_output` begin stderr lines
|
|
38
|
+
STDERR_END_MARKER = "^^^ STDERR ^^^" #: end stderr lines in :paramref:`ae.shell.sh_exec.lines_output`
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def debug_or_verbose(app_obj: Optional[ConsoleApp] = None) -> bool:
|
|
42
|
+
""" determine if the current app runs in debug|verbose mode, while preventing early .get_option() call an app init.
|
|
43
|
+
|
|
44
|
+
:param app_obj: optional ConsoleApp instance (def=main_app_instance()).
|
|
45
|
+
:return: a boolean False when the main app debug level is :data:`~ae.core.DEBUG_LEVEL_DISABLED`
|
|
46
|
+
and the app option 'more_verbose' is not specified (in cfg-file or at the command line),
|
|
47
|
+
else True.
|
|
48
|
+
|
|
49
|
+
.. note:: the return value on app startup/initialization, before the command line parsing, is always True.
|
|
50
|
+
|
|
51
|
+
.. hint::
|
|
52
|
+
the debug mode can be activated via the :class:`~ae.console.ConsoleApp` option `debug_level`, specified either
|
|
53
|
+
in a config file or via the command line options. the verbose mode get activated via the `more_verbose` option.
|
|
54
|
+
"""
|
|
55
|
+
app_obj = app_obj or main_app_instance()
|
|
56
|
+
# noinspection PyProtectedMember
|
|
57
|
+
return bool(
|
|
58
|
+
not app_obj # prevent exception in early app startup and in test runs
|
|
59
|
+
or app_obj.debug # main_app.debug_level > DEBUG_LEVEL_DISABLED
|
|
60
|
+
or not app_obj._parsed_arguments # pylint: disable=protected-access
|
|
61
|
+
or app_obj.get_option('more_verbose')) # optional app option
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_domain_user_var(variable_name: str, domain: str = "", user: str = "") -> Any:
|
|
65
|
+
""" determine the value of an OS environment variable for a specific domain and/or username.
|
|
66
|
+
|
|
67
|
+
:param variable_name: name of the config variable.
|
|
68
|
+
:param domain: name of the domain.
|
|
69
|
+
:param user: name/id of the user to get a user-specific value of.
|
|
70
|
+
:return: domain/user-specific value of the specified config variable.
|
|
71
|
+
"""
|
|
72
|
+
parts = (MAIN_SECTION_NAME, variable_name.lower(), f'AT_{norm_name(domain)}'.lower(), norm_name(user).lower())
|
|
73
|
+
value = None
|
|
74
|
+
if domain:
|
|
75
|
+
if user:
|
|
76
|
+
value = env_str('_'.join(parts), convert_name=True)
|
|
77
|
+
if value is None:
|
|
78
|
+
value = env_str('_'.join(parts[:-1]), convert_name=True)
|
|
79
|
+
elif user:
|
|
80
|
+
value = env_str('_'.join(parts[:2] + parts[-1:]), convert_name=True)
|
|
81
|
+
|
|
82
|
+
if value is None:
|
|
83
|
+
value = env_str('_'.join(parts[:2]), convert_name=True)
|
|
84
|
+
|
|
85
|
+
return value
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def hint(command: str, action: Union[Callable, str], message_suffix: str = "") -> str:
|
|
89
|
+
""" return hint string in debug/verbose mode, to be appended onto a shell/console output.
|
|
90
|
+
|
|
91
|
+
:param command: shell command.
|
|
92
|
+
:param action: shell command action function/method.
|
|
93
|
+
:param message_suffix: extra message text, added to the end of the returned console output string.
|
|
94
|
+
:return: in debug/verbose mode return a string with leading line feed to be sent
|
|
95
|
+
to console output, else return an empty string.
|
|
96
|
+
"""
|
|
97
|
+
if not isinstance(action, str):
|
|
98
|
+
action = action.__name__
|
|
99
|
+
return f"{os.linesep} (run: {command} {action}{message_suffix})" if debug_or_verbose() else ""
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@contextmanager
|
|
103
|
+
def in_os_env(start_dir: str = "") -> Iterator[MutableMapping[str, str]]:
|
|
104
|
+
""" temporarily add environment variables from the dotenv files that not exist in os.environ to it.
|
|
105
|
+
|
|
106
|
+
:param start_dir: path to the folder where the first dotenv file (with the highest priority) is stored.
|
|
107
|
+
:return: yielding the os env variables that got added to os.environ in this temporary context.
|
|
108
|
+
"""
|
|
109
|
+
loaded_env_vars = load_env_var_defaults(start_dir, os.environ)
|
|
110
|
+
try:
|
|
111
|
+
yield loaded_env_vars
|
|
112
|
+
finally:
|
|
113
|
+
for var_name in loaded_env_vars:
|
|
114
|
+
os.environ.pop(var_name)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@overload
|
|
118
|
+
def mask_token(text: str) -> str: ...
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@overload
|
|
122
|
+
def mask_token(text: list[str]) -> list[str]: ...
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def mask_token(text: Union[str, list[str]]) -> Union[str, list[str]]:
|
|
126
|
+
""" hide most parts of any GitHub/GitHub tokens found in the specified text/-lines.
|
|
127
|
+
|
|
128
|
+
:param text: text block, specified either as str object or as a list of str objects (lines),
|
|
129
|
+
to detect tokens within, to hide/mask the most part of them.
|
|
130
|
+
:return: text block with without the complete tokens.
|
|
131
|
+
|
|
132
|
+
.. note:: see also :func:`ae.base.mask_url` to hide passwords and tokens in URLs.
|
|
133
|
+
"""
|
|
134
|
+
if is_str_arg := isinstance(text, str):
|
|
135
|
+
lines = [text]
|
|
136
|
+
else:
|
|
137
|
+
lines = list(text) # copy to not change text list content
|
|
138
|
+
|
|
139
|
+
for tok_beg, tok_end in (('glpat-', '@gitlab.com'), ('ghp_', '@github.com')):
|
|
140
|
+
for idx, line in enumerate(lines):
|
|
141
|
+
while tok_beg in line: # hide the GitLab/GitHub private token, e.g. from git-push-urls with authentication
|
|
142
|
+
start = line.index(tok_beg)
|
|
143
|
+
end = line.find(tok_end, start)
|
|
144
|
+
if end == -1:
|
|
145
|
+
break
|
|
146
|
+
line = line[:start + 3] + "***-masked-token-***" + line[end - 3:]
|
|
147
|
+
lines[idx] = line
|
|
148
|
+
|
|
149
|
+
return lines[0] if is_str_arg else lines
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# pylint: disable-next=too-many-arguments,too-many-positional-arguments
|
|
153
|
+
def sh_exec(command_line: str, extra_args: Iterable[str] = (), console_input: str = "",
|
|
154
|
+
lines_output: Optional[list[str]] = None, app_obj: Optional[AppBase] = None, shell: bool = False,
|
|
155
|
+
env_vars: Optional[dict[str, str]] = None) -> int:
|
|
156
|
+
""" execute command in the current working directory of the OS console/shell.
|
|
157
|
+
|
|
158
|
+
:param command_line: command line string to execute on the console/shell. could contain command line args
|
|
159
|
+
separated by whitespace characters (alternatively use :paramref:`~sh_exec.extra_args`).
|
|
160
|
+
:param extra_args: optional sequence of extra command line arguments.
|
|
161
|
+
:param console_input: optional string to be sent to the stdin stream of the console/shell.
|
|
162
|
+
:param lines_output: optional list to be extended with the lines printed to stdout/stderr on execution.
|
|
163
|
+
by passing an empty list, the stdout and stderr streams/pipes will be separated,
|
|
164
|
+
resulting in having the stderr output lines at the end of the list, enclosed by
|
|
165
|
+
the list items :data:`STDERR_BEG_MARKER` and :data:`STDERR_END_MARKER`.
|
|
166
|
+
:param app_obj: optional :class:`~ae.core.AppBase`/:class:`~ae.console.ConsoleApp` instance, used for
|
|
167
|
+
logging. if not specified or None and if :func:`~ae.core.main_app_instance()` returns
|
|
168
|
+
None then the Python :func:`print` function is used.
|
|
169
|
+
specify :data:`~ae.base.UNSET` to suppress any printing/logging output.
|
|
170
|
+
:param shell: pass True to execute command in the default OS shell (see :meth:`subprocess.run`).
|
|
171
|
+
:param env_vars: OS shell environment variables to be used instead of the console/bash defaults.
|
|
172
|
+
:return: return code of the executed command or 126 if execution raised any other exception.
|
|
173
|
+
"""
|
|
174
|
+
args = command_line + " " + " ".join(extra_args) if shell else shlex.split(command_line) + list(extra_args)
|
|
175
|
+
ret_out = lines_output is not None # == isinstance(lines_output, list)
|
|
176
|
+
merge_err = bool(lines_output) # == -''- and len(lines_output) > 0
|
|
177
|
+
print_out = app_obj.po if app_obj else dummy_function if app_obj is UNSET else print
|
|
178
|
+
debug_out = app_obj.dpo if app_obj else dummy_function if app_obj is UNSET else print
|
|
179
|
+
debug_out(f" . executing at {os.getcwd()}: {mask_token(args)}")
|
|
180
|
+
|
|
181
|
+
result: Union[subprocess.CompletedProcess, subprocess.CalledProcessError] # having: stdout/stderr/returncode
|
|
182
|
+
try:
|
|
183
|
+
result = subprocess.run(args,
|
|
184
|
+
stdout=subprocess.PIPE if ret_out else None,
|
|
185
|
+
stderr=subprocess.STDOUT if merge_err else subprocess.PIPE if ret_out else None,
|
|
186
|
+
input=console_input.encode(),
|
|
187
|
+
check=True,
|
|
188
|
+
shell=shell,
|
|
189
|
+
env=env_vars)
|
|
190
|
+
except subprocess.CalledProcessError as ex: # pragma: no cover
|
|
191
|
+
debug_out(f"**** subprocess.run({mask_token(args)}) returned non-zero exit code {ex.returncode}; {ex=}")
|
|
192
|
+
result = ex
|
|
193
|
+
except Exception as ex: # pylint: disable=broad-except # pragma: no cover
|
|
194
|
+
print_out(f"**** subprocess.run({mask_token(args)}) raised exception {ex}")
|
|
195
|
+
return 126
|
|
196
|
+
|
|
197
|
+
if ret_out:
|
|
198
|
+
assert isinstance(lines_output, list), "silly mypy doesn't recognize ret_out"
|
|
199
|
+
if result.stdout:
|
|
200
|
+
lines_output.extend([line for line in result.stdout.decode().split(os.linesep) if line])
|
|
201
|
+
if not merge_err and result.stderr:
|
|
202
|
+
lines_output.append(STDERR_BEG_MARKER)
|
|
203
|
+
lines_output.extend([line for line in result.stderr.decode().split(os.linesep) if line])
|
|
204
|
+
lines_output.append(STDERR_END_MARKER)
|
|
205
|
+
|
|
206
|
+
return result.returncode
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# pylint: disable-next=too-many-arguments,too-many-positional-arguments
|
|
210
|
+
def sh_exit_if_exec_err(err_code: int, command_line: str,
|
|
211
|
+
extra_args: Iterable[str] = (), lines_output: Optional[list[str]] = None,
|
|
212
|
+
exit_on_err: bool = True, exit_msg: str = "", app_obj: Optional[ConsoleApp] = None,
|
|
213
|
+
shell: bool = False, env_vars: Optional[dict[str, str]] = None) -> int:
|
|
214
|
+
""" execute command in the current working directory of the OS console/shell, dump error, and exit app if needed.
|
|
215
|
+
|
|
216
|
+
:param err_code: error code to pass to the console as exit code if :paramref:`.exit_on_err` is True.
|
|
217
|
+
:param command_line: command line string to execute on the console/shell. could contain command line args
|
|
218
|
+
separated by whitespace characters (alternatively use :paramref:`~sh_exec.extra_args`).
|
|
219
|
+
:param extra_args: optional iterable of extra command line arguments.
|
|
220
|
+
:param lines_output: optional list to return the lines printed to stdout/stderr on execution.
|
|
221
|
+
by passing an empty list, the stdout and stderr streams/pipes will be separated,
|
|
222
|
+
resulting in having the stderr output lines at the end of the list. specify at
|
|
223
|
+
least on list item to merge-in the stderr output (into the stdout output and return).
|
|
224
|
+
:param exit_on_err: pass False to **not** exit the app on error (:paramref:`.exit_msg` has then to be
|
|
225
|
+
empty).
|
|
226
|
+
:param exit_msg: additional text to print on stdout/console if the app debug level is greater or equal
|
|
227
|
+
to 1 or if an error occurred and :paramref:`~sh_exit_if_exec_err.exit_on_err` is True.
|
|
228
|
+
:param app_obj: :class:`~ae.console.ConsoleApp` instance, used for logging/force-ignorable error.
|
|
229
|
+
:param shell: pass True to execute command in the default OS shell (see :meth:`subprocess.run`).
|
|
230
|
+
:param env_vars: OS shell environment variables to be used instead of the console/bash defaults.
|
|
231
|
+
:return: 0 on success or the error number if an error occurred.
|
|
232
|
+
"""
|
|
233
|
+
assert exit_on_err or not exit_msg, "specified exit message will never be shown because exit_on_err is False"
|
|
234
|
+
if lines_output is None:
|
|
235
|
+
lines_output = []
|
|
236
|
+
app_obj = app_obj or cast(ConsoleApp, main_app_instance()) # calls app_obj./ConsoleApp.chk() method
|
|
237
|
+
|
|
238
|
+
sh_err = sh_exec(command_line, extra_args=extra_args,
|
|
239
|
+
lines_output=lines_output, app_obj=app_obj, shell=shell, env_vars=env_vars)
|
|
240
|
+
|
|
241
|
+
if app_obj and (sh_err and exit_on_err or app_obj.debug):
|
|
242
|
+
for line in lines_output:
|
|
243
|
+
if app_obj.verbose or not line.startswith("LOG: "): # if verbose show mypy's endless (stderr) log entries
|
|
244
|
+
app_obj.po(" " * 6 + line)
|
|
245
|
+
msg = f"command: {command_line} " + " ".join('"' + arg + '"' if " " in arg else arg for arg in extra_args)
|
|
246
|
+
if not sh_err:
|
|
247
|
+
app_obj.dpo(f" = successfully executed {mask_token(msg)}")
|
|
248
|
+
else:
|
|
249
|
+
if exit_msg:
|
|
250
|
+
app_obj.po(f" {exit_msg}")
|
|
251
|
+
app_obj.chk(err_code, not exit_on_err, f"sh_exit_if_exec_err error {sh_err} in {mask_token(msg)}") # quit
|
|
252
|
+
|
|
253
|
+
return sh_err
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ae_shell
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: ae namespace module portion shell: shell execution and environment helpers
|
|
5
5
|
Home-page: https://gitlab.com/ae-group/ae_shell
|
|
6
6
|
Author: AndiEcker
|
|
@@ -16,7 +16,7 @@ Classifier: Natural Language :: English
|
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Requires-Python: >=3.9
|
|
@@ -65,13 +65,13 @@ Dynamic: summary
|
|
|
65
65
|
|
|
66
66
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.101 -->
|
|
67
67
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.22 -->
|
|
68
|
-
# shell 0.3.
|
|
68
|
+
# shell 0.3.8
|
|
69
69
|
|
|
70
70
|
[](
|
|
71
71
|
https://gitlab.com/ae-group/ae_shell)
|
|
72
72
|
[](
|
|
74
|
+
https://gitlab.com/ae-group/ae_shell/-/tree/release0.3.8)
|
|
75
75
|
[](
|
|
76
76
|
https://pypi.org/project/ae-shell/#history)
|
|
77
77
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.project_tpls v0.3.
|
|
1
|
+
# THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.project_tpls v0.3.68
|
|
2
2
|
""" setup of ae namespace module portion shell: shell execution and environment helpers. """
|
|
3
3
|
# noinspection PyUnresolvedReferences
|
|
4
4
|
import sys
|
|
@@ -12,7 +12,7 @@ setup_kwargs = {
|
|
|
12
12
|
'author_email': 'aecker2@gmail.com',
|
|
13
13
|
'classifiers': [ 'Development Status :: 3 - Alpha', 'Natural Language :: English', 'Operating System :: OS Independent',
|
|
14
14
|
'Programming Language :: Python', 'Programming Language :: Python :: 3',
|
|
15
|
-
'Programming Language :: Python :: 3.
|
|
15
|
+
'Programming Language :: Python :: 3.12', 'Topic :: Software Development :: Libraries :: Python Modules',
|
|
16
16
|
'Typing :: Typed'],
|
|
17
17
|
'description': 'ae namespace module portion shell: shell execution and environment helpers',
|
|
18
18
|
'extras_require': { 'dev': [ 'aedev_project_tpls', 'ae_ae', 'anybadge', 'coverage-badge', 'aedev_project_manager', 'flake8',
|
|
@@ -25,13 +25,13 @@ setup_kwargs = {
|
|
|
25
25
|
'license': 'GPL-3.0-or-later',
|
|
26
26
|
'long_description': ('<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.101 -->\n'
|
|
27
27
|
'<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.22 -->\n'
|
|
28
|
-
'# shell 0.3.
|
|
28
|
+
'# shell 0.3.8\n'
|
|
29
29
|
'\n'
|
|
30
30
|
'[](\n'
|
|
31
31
|
' https://gitlab.com/ae-group/ae_shell)\n'
|
|
32
32
|
'[](\n'
|
|
34
|
+
' https://gitlab.com/ae-group/ae_shell/-/tree/release0.3.8)\n'
|
|
35
35
|
'[](\n'
|
|
36
36
|
' https://pypi.org/project/ae-shell/#history)\n'
|
|
37
37
|
'\n'
|
|
@@ -108,7 +108,7 @@ setup_kwargs = {
|
|
|
108
108
|
'Source': 'https://ae.readthedocs.io/en/latest/_modules/ae/shell.html'},
|
|
109
109
|
'python_requires': '>=3.9',
|
|
110
110
|
'url': 'https://gitlab.com/ae-group/ae_shell',
|
|
111
|
-
'version': '0.3.
|
|
111
|
+
'version': '0.3.8',
|
|
112
112
|
'zip_safe': True,
|
|
113
113
|
}
|
|
114
114
|
|