reaxkit 1.0.0__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.
- reaxkit/__init__.py +0 -0
- reaxkit/analysis/__init__.py +0 -0
- reaxkit/analysis/composed/RDF_analyzer.py +560 -0
- reaxkit/analysis/composed/__init__.py +0 -0
- reaxkit/analysis/composed/connectivity_analyzer.py +706 -0
- reaxkit/analysis/composed/coordination_analyzer.py +144 -0
- reaxkit/analysis/composed/electrostatics_analyzer.py +687 -0
- reaxkit/analysis/per_file/__init__.py +0 -0
- reaxkit/analysis/per_file/control_analyzer.py +165 -0
- reaxkit/analysis/per_file/eregime_analyzer.py +108 -0
- reaxkit/analysis/per_file/ffield_analyzer.py +305 -0
- reaxkit/analysis/per_file/fort13_analyzer.py +79 -0
- reaxkit/analysis/per_file/fort57_analyzer.py +106 -0
- reaxkit/analysis/per_file/fort73_analyzer.py +61 -0
- reaxkit/analysis/per_file/fort74_analyzer.py +65 -0
- reaxkit/analysis/per_file/fort76_analyzer.py +191 -0
- reaxkit/analysis/per_file/fort78_analyzer.py +154 -0
- reaxkit/analysis/per_file/fort79_analyzer.py +83 -0
- reaxkit/analysis/per_file/fort7_analyzer.py +393 -0
- reaxkit/analysis/per_file/fort99_analyzer.py +411 -0
- reaxkit/analysis/per_file/molfra_analyzer.py +359 -0
- reaxkit/analysis/per_file/params_analyzer.py +258 -0
- reaxkit/analysis/per_file/summary_analyzer.py +84 -0
- reaxkit/analysis/per_file/trainset_analyzer.py +84 -0
- reaxkit/analysis/per_file/vels_analyzer.py +95 -0
- reaxkit/analysis/per_file/xmolout_analyzer.py +528 -0
- reaxkit/cli.py +181 -0
- reaxkit/count_loc.py +276 -0
- reaxkit/data/alias.yaml +89 -0
- reaxkit/data/constants.yaml +27 -0
- reaxkit/data/reaxff_input_files_contents.yaml +186 -0
- reaxkit/data/reaxff_output_files_contents.yaml +301 -0
- reaxkit/data/units.yaml +38 -0
- reaxkit/help/__init__.py +0 -0
- reaxkit/help/help_index_loader.py +531 -0
- reaxkit/help/introspection_utils.py +131 -0
- reaxkit/io/__init__.py +0 -0
- reaxkit/io/base_handler.py +165 -0
- reaxkit/io/generators/__init__.py +0 -0
- reaxkit/io/generators/control_generator.py +123 -0
- reaxkit/io/generators/eregime_generator.py +341 -0
- reaxkit/io/generators/geo_generator.py +967 -0
- reaxkit/io/generators/trainset_generator.py +1758 -0
- reaxkit/io/generators/tregime_generator.py +113 -0
- reaxkit/io/generators/vregime_generator.py +164 -0
- reaxkit/io/generators/xmolout_generator.py +304 -0
- reaxkit/io/handlers/__init__.py +0 -0
- reaxkit/io/handlers/control_handler.py +209 -0
- reaxkit/io/handlers/eregime_handler.py +122 -0
- reaxkit/io/handlers/ffield_handler.py +812 -0
- reaxkit/io/handlers/fort13_handler.py +123 -0
- reaxkit/io/handlers/fort57_handler.py +143 -0
- reaxkit/io/handlers/fort73_handler.py +145 -0
- reaxkit/io/handlers/fort74_handler.py +155 -0
- reaxkit/io/handlers/fort76_handler.py +195 -0
- reaxkit/io/handlers/fort78_handler.py +142 -0
- reaxkit/io/handlers/fort79_handler.py +227 -0
- reaxkit/io/handlers/fort7_handler.py +264 -0
- reaxkit/io/handlers/fort99_handler.py +128 -0
- reaxkit/io/handlers/geo_handler.py +224 -0
- reaxkit/io/handlers/molfra_handler.py +184 -0
- reaxkit/io/handlers/params_handler.py +137 -0
- reaxkit/io/handlers/summary_handler.py +135 -0
- reaxkit/io/handlers/trainset_handler.py +658 -0
- reaxkit/io/handlers/vels_handler.py +293 -0
- reaxkit/io/handlers/xmolout_handler.py +174 -0
- reaxkit/utils/__init__.py +0 -0
- reaxkit/utils/alias.py +219 -0
- reaxkit/utils/cache.py +77 -0
- reaxkit/utils/constants.py +75 -0
- reaxkit/utils/equation_of_states.py +96 -0
- reaxkit/utils/exceptions.py +27 -0
- reaxkit/utils/frame_utils.py +175 -0
- reaxkit/utils/log.py +43 -0
- reaxkit/utils/media/__init__.py +0 -0
- reaxkit/utils/media/convert.py +90 -0
- reaxkit/utils/media/make_video.py +91 -0
- reaxkit/utils/media/plotter.py +812 -0
- reaxkit/utils/numerical/__init__.py +0 -0
- reaxkit/utils/numerical/extrema_finder.py +96 -0
- reaxkit/utils/numerical/moving_average.py +103 -0
- reaxkit/utils/numerical/numerical_calcs.py +75 -0
- reaxkit/utils/numerical/signal_ops.py +135 -0
- reaxkit/utils/path.py +55 -0
- reaxkit/utils/units.py +104 -0
- reaxkit/webui/__init__.py +0 -0
- reaxkit/webui/app.py +0 -0
- reaxkit/webui/components.py +0 -0
- reaxkit/webui/layouts.py +0 -0
- reaxkit/webui/utils.py +0 -0
- reaxkit/workflows/__init__.py +0 -0
- reaxkit/workflows/composed/__init__.py +0 -0
- reaxkit/workflows/composed/coordination_workflow.py +393 -0
- reaxkit/workflows/composed/electrostatics_workflow.py +587 -0
- reaxkit/workflows/composed/xmolout_fort7_workflow.py +343 -0
- reaxkit/workflows/meta/__init__.py +0 -0
- reaxkit/workflows/meta/help_workflow.py +136 -0
- reaxkit/workflows/meta/introspection_workflow.py +235 -0
- reaxkit/workflows/meta/make_video_workflow.py +61 -0
- reaxkit/workflows/meta/plotter_workflow.py +601 -0
- reaxkit/workflows/per_file/__init__.py +0 -0
- reaxkit/workflows/per_file/control_workflow.py +110 -0
- reaxkit/workflows/per_file/eregime_workflow.py +267 -0
- reaxkit/workflows/per_file/ffield_workflow.py +390 -0
- reaxkit/workflows/per_file/fort13_workflow.py +86 -0
- reaxkit/workflows/per_file/fort57_workflow.py +137 -0
- reaxkit/workflows/per_file/fort73_workflow.py +151 -0
- reaxkit/workflows/per_file/fort74_workflow.py +88 -0
- reaxkit/workflows/per_file/fort76_workflow.py +188 -0
- reaxkit/workflows/per_file/fort78_workflow.py +135 -0
- reaxkit/workflows/per_file/fort79_workflow.py +314 -0
- reaxkit/workflows/per_file/fort7_workflow.py +592 -0
- reaxkit/workflows/per_file/fort83_workflow.py +60 -0
- reaxkit/workflows/per_file/fort99_workflow.py +223 -0
- reaxkit/workflows/per_file/geo_workflow.py +554 -0
- reaxkit/workflows/per_file/molfra_workflow.py +577 -0
- reaxkit/workflows/per_file/params_workflow.py +135 -0
- reaxkit/workflows/per_file/summary_workflow.py +161 -0
- reaxkit/workflows/per_file/trainset_workflow.py +356 -0
- reaxkit/workflows/per_file/tregime_workflow.py +79 -0
- reaxkit/workflows/per_file/vels_workflow.py +309 -0
- reaxkit/workflows/per_file/vregime_workflow.py +75 -0
- reaxkit/workflows/per_file/xmolout_workflow.py +678 -0
- reaxkit-1.0.0.dist-info/METADATA +128 -0
- reaxkit-1.0.0.dist-info/RECORD +130 -0
- reaxkit-1.0.0.dist-info/WHEEL +5 -0
- reaxkit-1.0.0.dist-info/entry_points.txt +2 -0
- reaxkit-1.0.0.dist-info/licenses/AUTHORS.md +20 -0
- reaxkit-1.0.0.dist-info/licenses/LICENSE +21 -0
- reaxkit-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI workflow for introspecting ReaxKit modules and folders.
|
|
3
|
+
|
|
4
|
+
This workflow powers the `reaxkit intspec` command, allowing users to:
|
|
5
|
+
- Inspect a single Python module and view its top-level docstring summary
|
|
6
|
+
along with public functions/classes and their one-line descriptions.
|
|
7
|
+
- Recursively scan a folder or package and list all contained `.py` files
|
|
8
|
+
with their module docstring first lines.
|
|
9
|
+
|
|
10
|
+
It is designed as a lightweight discovery and navigation tool to help users
|
|
11
|
+
understand what functionality exists inside ReaxKit without opening files
|
|
12
|
+
manually.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import importlib
|
|
20
|
+
import os
|
|
21
|
+
from typing import List, Optional, Tuple
|
|
22
|
+
|
|
23
|
+
from tabulate import tabulate
|
|
24
|
+
|
|
25
|
+
from reaxkit.help.introspection_utils import (
|
|
26
|
+
list_modules_recursive_with_summaries,
|
|
27
|
+
module_docstring_first_line_from_file,
|
|
28
|
+
public_symbols_from_file,
|
|
29
|
+
resolve_module_hint_to_file,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Try exact first, then common prefixes
|
|
33
|
+
CANDIDATE_PREFIXES: List[str] = [
|
|
34
|
+
"", # fully-qualified or exact
|
|
35
|
+
"reaxkit.analysis.",
|
|
36
|
+
"reaxkit.analysis.composed.",
|
|
37
|
+
"reaxkit.analysis.per_file.",
|
|
38
|
+
"reaxkit.workflows.",
|
|
39
|
+
"reaxkit.workflows.per_file.",
|
|
40
|
+
"reaxkit.workflows.composed.",
|
|
41
|
+
"reaxkit.workflows.meta.",
|
|
42
|
+
"reaxkit.io.",
|
|
43
|
+
"reaxkit.io.handlers.",
|
|
44
|
+
"reaxkit.io.generators.",
|
|
45
|
+
"reaxkit.utils.",
|
|
46
|
+
"reaxkit.utils.media.",
|
|
47
|
+
"reaxkit.utils.numerical.",
|
|
48
|
+
"reaxkit.help.",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
# Canonical roots for folder short-hands like "workflow" / "analysis"
|
|
52
|
+
FOLDER_ROOTS: List[str] = [
|
|
53
|
+
"reaxkit.analysis",
|
|
54
|
+
"reaxkit.workflows",
|
|
55
|
+
"reaxkit.io",
|
|
56
|
+
"reaxkit.utils",
|
|
57
|
+
"reaxkit.help",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _print_table(rows: List[Tuple[str, str]], headers: Tuple[str, str]) -> int:
|
|
62
|
+
if not rows:
|
|
63
|
+
print("No items found.")
|
|
64
|
+
return 0
|
|
65
|
+
print(tabulate(rows, headers=headers, tablefmt="grid"))
|
|
66
|
+
return 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _resolve_pkg_dir_from_module_name(modname: str) -> Optional[str]:
|
|
70
|
+
try:
|
|
71
|
+
mod = importlib.import_module(modname)
|
|
72
|
+
if getattr(mod, "__path__", None):
|
|
73
|
+
return next(iter(mod.__path__))
|
|
74
|
+
return None
|
|
75
|
+
except Exception:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _looks_like_path(hint: str) -> bool:
|
|
80
|
+
return hint.endswith(".py") or ("/" in hint) or ("\\" in hint) or (os.sep in hint)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _resolve_folder_hint_to_dir(folder_hint: str) -> Optional[str]:
|
|
84
|
+
"""
|
|
85
|
+
Accepts:
|
|
86
|
+
- filesystem directory (e.g., reaxkit/workflows)
|
|
87
|
+
- dotted package (e.g., reaxkit.workflows)
|
|
88
|
+
- shorthand (e.g., workflow/workflows, analysis, io, utils)
|
|
89
|
+
"""
|
|
90
|
+
# Direct directory path
|
|
91
|
+
if os.path.isdir(folder_hint):
|
|
92
|
+
return os.path.abspath(folder_hint)
|
|
93
|
+
|
|
94
|
+
# Dotted package
|
|
95
|
+
d = _resolve_pkg_dir_from_module_name(folder_hint)
|
|
96
|
+
if d:
|
|
97
|
+
return d
|
|
98
|
+
|
|
99
|
+
# Normalize singular/plural shorthand
|
|
100
|
+
leafs = {folder_hint.strip()}
|
|
101
|
+
if folder_hint.endswith("s"):
|
|
102
|
+
leafs.add(folder_hint[:-1])
|
|
103
|
+
else:
|
|
104
|
+
leafs.add(folder_hint + "s")
|
|
105
|
+
|
|
106
|
+
# Try mapping shorthand to known ReaxKit roots
|
|
107
|
+
for root in FOLDER_ROOTS:
|
|
108
|
+
for leaf in leafs:
|
|
109
|
+
# e.g., reaxkit.workflows (leaf == "workflow"/"workflows") → match root itself
|
|
110
|
+
if leaf in {"workflow", "workflows"} and root == "reaxkit.workflows":
|
|
111
|
+
d = _resolve_pkg_dir_from_module_name(root)
|
|
112
|
+
if d:
|
|
113
|
+
return d
|
|
114
|
+
|
|
115
|
+
# e.g., folder_hint="meta" → try reaxkit.workflows.meta
|
|
116
|
+
d = _resolve_pkg_dir_from_module_name(f"{root}.{leaf}")
|
|
117
|
+
if d:
|
|
118
|
+
return d
|
|
119
|
+
|
|
120
|
+
# Finally, try direct roots by their last component
|
|
121
|
+
for root in FOLDER_ROOTS:
|
|
122
|
+
d = _resolve_pkg_dir_from_module_name(root)
|
|
123
|
+
if d and os.path.basename(d) in leafs:
|
|
124
|
+
return d
|
|
125
|
+
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def build_parser(p: argparse.ArgumentParser) -> None:
|
|
130
|
+
"""Define CLI args for `reaxkit intspec` (kind-level)."""
|
|
131
|
+
g = p.add_mutually_exclusive_group(required=True)
|
|
132
|
+
g.add_argument("--file", help="Module name (e.g. fort7_analyzer) or path to .py")
|
|
133
|
+
g.add_argument("--folder", help="Folder/package (e.g. workflow, workflows, reaxkit/workflows)")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# ------------------------- FILE MODE -------------------------
|
|
137
|
+
|
|
138
|
+
def run_file(module_hint: str) -> int:
|
|
139
|
+
"""
|
|
140
|
+
Show:
|
|
141
|
+
- module docstring first line
|
|
142
|
+
- table of public functions/classes with docstring first line
|
|
143
|
+
"""
|
|
144
|
+
pyfile: Optional[str] = None
|
|
145
|
+
|
|
146
|
+
# 1) direct path
|
|
147
|
+
if _looks_like_path(module_hint):
|
|
148
|
+
if os.path.isfile(module_hint):
|
|
149
|
+
pyfile = os.path.abspath(module_hint)
|
|
150
|
+
else:
|
|
151
|
+
print(f"File not found: {module_hint}")
|
|
152
|
+
return 1
|
|
153
|
+
else:
|
|
154
|
+
# 2) fully-qualified or prefixed module name resolution
|
|
155
|
+
tried: List[str] = []
|
|
156
|
+
for prefix in CANDIDATE_PREFIXES:
|
|
157
|
+
name = prefix + module_hint
|
|
158
|
+
tried.append(name)
|
|
159
|
+
pyfile = resolve_module_hint_to_file(name)
|
|
160
|
+
if pyfile:
|
|
161
|
+
break
|
|
162
|
+
|
|
163
|
+
if not pyfile:
|
|
164
|
+
print("Could not resolve module to a .py file. Tried:")
|
|
165
|
+
for t in tried:
|
|
166
|
+
print(f" - {t}")
|
|
167
|
+
return 1
|
|
168
|
+
|
|
169
|
+
# Print module docstring first line
|
|
170
|
+
mod_sum = module_docstring_first_line_from_file(pyfile)
|
|
171
|
+
print(f"\nModule: {module_hint}")
|
|
172
|
+
print(f"File: {pyfile}")
|
|
173
|
+
print(f"Doc: {mod_sum}\n")
|
|
174
|
+
|
|
175
|
+
# Print public symbols table
|
|
176
|
+
syms = public_symbols_from_file(pyfile)
|
|
177
|
+
rows = [(s.kind, s.name, s.summary) for s in syms]
|
|
178
|
+
if not rows:
|
|
179
|
+
print("No public functions/classes found.")
|
|
180
|
+
return 0
|
|
181
|
+
|
|
182
|
+
print(tabulate(rows, headers=("Kind", "Name", "Summary"), tablefmt="grid"))
|
|
183
|
+
return 0
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# ------------------------- FOLDER MODE -------------------------
|
|
187
|
+
|
|
188
|
+
def run_folder(folder_hint: str) -> int:
|
|
189
|
+
"""
|
|
190
|
+
Recursively list all .py files under the folder/package with module docstring first line.
|
|
191
|
+
"""
|
|
192
|
+
pkg_dir = _resolve_folder_hint_to_dir(folder_hint)
|
|
193
|
+
if not pkg_dir:
|
|
194
|
+
print(f"Could not resolve folder '{folder_hint}' to a package directory.")
|
|
195
|
+
return 1
|
|
196
|
+
|
|
197
|
+
rows = list_modules_recursive_with_summaries(pkg_dir)
|
|
198
|
+
# Use relative path as the "name" so nested folders are visible
|
|
199
|
+
return _print_table(rows, headers=("Module (.py under folder)", "Docstring (1st line)"))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# ------------------------- main glue -------------------------
|
|
203
|
+
|
|
204
|
+
def run_main(file: str | None, folder: str | None) -> int:
|
|
205
|
+
"""
|
|
206
|
+
- If --file: show module docstring + public symbol summary table
|
|
207
|
+
- If --folder: recursively list .py files + module docstrings
|
|
208
|
+
"""
|
|
209
|
+
if bool(file) == bool(folder):
|
|
210
|
+
print("Please pass exactly one of: --file <module> OR --folder <package/folder>")
|
|
211
|
+
return 2
|
|
212
|
+
if file:
|
|
213
|
+
return run_file(file)
|
|
214
|
+
return run_folder(folder) # type: ignore[arg-type]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def register_tasks(subparsers) -> None:
|
|
218
|
+
"""Task-level entry: `reaxkit intspec run ...`."""
|
|
219
|
+
p = subparsers.add_parser(
|
|
220
|
+
"run",
|
|
221
|
+
help="Introspect a module (--file) or folder (--folder).",
|
|
222
|
+
description=(
|
|
223
|
+
"Introspect a module (--file) or folder (--folder).\n"
|
|
224
|
+
"Examples:\n"
|
|
225
|
+
" reaxkit intspec --folder workflow\n"
|
|
226
|
+
" reaxkit intspec run --folder workflow\n"
|
|
227
|
+
" reaxkit intspec --file fort7_analyzer\n"
|
|
228
|
+
" reaxkit intspec run --file fort7_analyzer\n"
|
|
229
|
+
),
|
|
230
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
231
|
+
)
|
|
232
|
+
g = p.add_mutually_exclusive_group(required=True)
|
|
233
|
+
g.add_argument("--file", help="Module name (e.g. fort7_analyzer) or path to .py")
|
|
234
|
+
g.add_argument("--folder", help="Folder/package (e.g. workflow, workflows, reaxkit/workflows)")
|
|
235
|
+
p.set_defaults(_run=lambda args: run_main(getattr(args, "file", None), getattr(args, "folder", None)))
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Video generation workflow for ReaxKit.
|
|
3
|
+
|
|
4
|
+
This workflow provides utilities for creating video files (e.g. MP4)
|
|
5
|
+
from a sequence of image files stored in a directory.
|
|
6
|
+
|
|
7
|
+
It is primarily intended for post-processing and visualization of
|
|
8
|
+
ReaxKit outputs, such as:
|
|
9
|
+
- frame-by-frame 3D scatter plots,
|
|
10
|
+
- time-resolved heatmaps,
|
|
11
|
+
- or any other analysis that produces ordered image sequences.
|
|
12
|
+
|
|
13
|
+
The workflow wraps simple image-to-video functionality and exposes it
|
|
14
|
+
through a CLI task for reproducible and scriptable media generation.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
import argparse
|
|
20
|
+
from reaxkit.utils.media.make_video import images_to_video
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _make_task(args: argparse.Namespace) -> int:
|
|
24
|
+
"""Create a video from images in a folder."""
|
|
25
|
+
exts = tuple(e.strip() for e in args.ext.split(","))
|
|
26
|
+
out_path = images_to_video(
|
|
27
|
+
folder_path=args.folder,
|
|
28
|
+
output_file=args.output,
|
|
29
|
+
fps=args.fps,
|
|
30
|
+
ext=exts,
|
|
31
|
+
)
|
|
32
|
+
print(f"[Done] Video saved to {args.output}")
|
|
33
|
+
return 0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def register_tasks(subparsers: argparse._SubParsersAction) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Register coordination-related CLI subcommands.
|
|
39
|
+
|
|
40
|
+
This function defines the task-level interface for the
|
|
41
|
+
`reaxkit file` workflow and attaches its tasks (i.e., subcommands).
|
|
42
|
+
|
|
43
|
+
Each task may share common input arguments and defines task-specific options as needed.
|
|
44
|
+
"""
|
|
45
|
+
p = subparsers.add_parser(
|
|
46
|
+
"make",
|
|
47
|
+
help="Create a video from a sequence of image files",
|
|
48
|
+
description=(
|
|
49
|
+
"Examples:\n"
|
|
50
|
+
" reaxkit video make --folder reaxkit_outputs/elect/local_mu_3d "
|
|
51
|
+
"--output reaxkit_outputs/video/local_mu_3D.mp4 --fps 5\n"
|
|
52
|
+
),
|
|
53
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
54
|
+
)
|
|
55
|
+
p.add_argument("--folder", default=".", help="Folder containing image files (default: current directory)")
|
|
56
|
+
p.add_argument("--output", default="reaxkit_outputs/video/output_video.mp4", help="Output video filename")
|
|
57
|
+
p.add_argument("--fps", type=int, default=10, help="Frames per second (default: 10)")
|
|
58
|
+
p.add_argument("--ext", default=".png,.jpg,.jpeg",
|
|
59
|
+
help="Comma-separated list of accepted image extensions (default: .png,.jpg,.jpeg)",
|
|
60
|
+
)
|
|
61
|
+
p.set_defaults(_run=_make_task)
|