mmif-python 1.2.0__tar.gz → 1.2.1__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.
- {mmif_python-1.2.0/mmif_python.egg-info → mmif_python-1.2.1}/PKG-INFO +1 -1
- mmif_python-1.2.1/VERSION +1 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/annotation.py +1 -1
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/mmif.py +1 -1
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/view.py +1 -1
- mmif_python-1.2.1/mmif/utils/cli/describe.py +140 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/cli/rewind.py +15 -22
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/cli/source.py +1 -1
- mmif_python-1.2.1/mmif/utils/workflow_helper.py +466 -0
- mmif_python-1.2.1/mmif/ver/__init__.py +2 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1/mmif_python.egg-info}/PKG-INFO +1 -1
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/SOURCES.txt +1 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/tests/test_utils.py +63 -0
- mmif_python-1.2.1/tests/test_utils_cli.py +306 -0
- mmif_python-1.2.0/VERSION +0 -1
- mmif_python-1.2.0/mmif/utils/cli/describe.py +0 -333
- mmif_python-1.2.0/mmif/ver/__init__.py +0 -2
- mmif_python-1.2.0/tests/test_utils_cli.py +0 -170
- {mmif_python-1.2.0 → mmif_python-1.2.1}/LICENSE +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/MANIFEST.in +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/README.md +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/__init__.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/res/__init__.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/res/clams.vocabulary.yaml +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/res/do-not-edit.txt +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/res/mmif.json +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/__init__.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/model.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/__init__.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/cli/__init__.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/sequence_helper.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/text_document_helper.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/timeunit_helper.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/video_document_helper.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/ver/do-not-edit.txt +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/__init__.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/annotation_types.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/base_types.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/do-not-edit.txt +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/document_types.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_docloc_http/__init__.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/dependency_links.txt +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/entry_points.txt +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/requires.txt +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/top_level.txt +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/requirements.cv +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/requirements.seq +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/requirements.txt +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/setup.cfg +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/setup.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/tests/test_serialize.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/tests/test_versioncompat.py +0 -0
- {mmif_python-1.2.0 → mmif_python-1.2.1}/tests/test_vocab.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mmif-python
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Python implementation of MultiMedia Interchange Format specification. (https://mmif.clams.ai)
|
|
5
5
|
Home-page: https://mmif.clams.ai
|
|
6
6
|
Author: Brandeis Lab for Linguistics and Computation
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.2.1
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
The :mod:`annotation` module contains the classes used to represent a
|
|
3
3
|
MMIF annotation as a live Python object.
|
|
4
4
|
|
|
5
|
-
In MMIF, annotations are created by apps in a
|
|
5
|
+
In MMIF, annotations are created by apps in a workflow as a part
|
|
6
6
|
of a view. For documentation on how views are represented, see
|
|
7
7
|
:mod:`mmif.serialize.view`.
|
|
8
8
|
"""
|
|
@@ -635,7 +635,7 @@ class Mmif(MmifObject):
|
|
|
635
635
|
def get_views_for_document(self, doc_id: str) -> List[View]:
|
|
636
636
|
"""
|
|
637
637
|
Returns the list of all views that have annotations anchored on a particular document.
|
|
638
|
-
Note that when the document is inside a view (generated during the
|
|
638
|
+
Note that when the document is inside a view (generated during the workflow's running),
|
|
639
639
|
doc_id must be prefixed with the view_id.
|
|
640
640
|
"""
|
|
641
641
|
views = []
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
The :mod:`view` module contains the classes used to represent a MMIF view
|
|
3
3
|
as a live Python object.
|
|
4
4
|
|
|
5
|
-
In MMIF, views are created by apps in a
|
|
5
|
+
In MMIF, views are created by apps in a workflow that are annotating
|
|
6
6
|
data that was previously present in the MMIF file.
|
|
7
7
|
|
|
8
8
|
The :class:`View` class is a high-level container that provides convenient
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
import textwrap
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
from mmif.utils.workflow_helper import generate_workflow_identifier, describe_single_mmif, \
|
|
9
|
+
describe_mmif_collection
|
|
10
|
+
# gen_param_hash is imported for backward compatibility
|
|
11
|
+
from mmif.utils.workflow_helper import generate_param_hash
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_pipeline_specs(mmif_file: Union[str, Path]):
|
|
15
|
+
import warnings
|
|
16
|
+
warnings.warn("get_pipeline_specs is deprecated, use mmif.utils.workflow_helper.describe_single_mmif instead",
|
|
17
|
+
DeprecationWarning)
|
|
18
|
+
return describe_single_mmif(mmif_file)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def generate_pipeline_identifier(mmif_file: Union[str, Path]) -> str:
|
|
22
|
+
import warnings
|
|
23
|
+
warnings.warn("generate_pipeline_identifier is deprecated, use generate_workflow_identifier instead",
|
|
24
|
+
DeprecationWarning)
|
|
25
|
+
return generate_workflow_identifier(mmif_file)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def describe_argparser():
|
|
29
|
+
"""
|
|
30
|
+
Returns two strings: one-line description of the argparser, and
|
|
31
|
+
additional material, which will be shown in `clams --help` and
|
|
32
|
+
`clams <subcmd> --help`, respectively.
|
|
33
|
+
"""
|
|
34
|
+
oneliner = (
|
|
35
|
+
'provides CLI to describe the workflow specification from a MMIF '
|
|
36
|
+
'file or a collection of MMIF files.'
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# get and clean docstrings
|
|
40
|
+
single_doc = describe_single_mmif.__doc__.split(':param')[0]
|
|
41
|
+
single_doc = textwrap.dedent(single_doc).strip()
|
|
42
|
+
collection_doc = describe_mmif_collection.__doc__.split(':param')[0]
|
|
43
|
+
collection_doc = textwrap.dedent(collection_doc).strip()
|
|
44
|
+
|
|
45
|
+
additional = textwrap.dedent(f"""
|
|
46
|
+
This command extracts workflow information from a single MMIF file or
|
|
47
|
+
summarizes a directory of MMIF files.
|
|
48
|
+
|
|
49
|
+
==========================
|
|
50
|
+
For a single MMIF file
|
|
51
|
+
==========================
|
|
52
|
+
{single_doc}
|
|
53
|
+
|
|
54
|
+
===============================
|
|
55
|
+
For a directory of MMIF files
|
|
56
|
+
===============================
|
|
57
|
+
{collection_doc}
|
|
58
|
+
""")
|
|
59
|
+
return oneliner, oneliner + '\n\n' + additional.strip()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def prep_argparser(**kwargs):
|
|
63
|
+
parser = argparse.ArgumentParser(
|
|
64
|
+
description=describe_argparser()[1],
|
|
65
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
66
|
+
**kwargs
|
|
67
|
+
)
|
|
68
|
+
parser.add_argument(
|
|
69
|
+
"MMIF_FILE",
|
|
70
|
+
nargs="?",
|
|
71
|
+
type=str,
|
|
72
|
+
default=None if sys.stdin.isatty() else sys.stdin,
|
|
73
|
+
help='input MMIF file, a directory of MMIF files, or STDIN if `-` or not provided.'
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"-o", "--output",
|
|
77
|
+
type=argparse.FileType("w"),
|
|
78
|
+
default=sys.stdout,
|
|
79
|
+
help='output file path, or STDOUT if not provided.'
|
|
80
|
+
)
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"-p", "--pretty",
|
|
83
|
+
action="store_true",
|
|
84
|
+
help="Pretty-print JSON output"
|
|
85
|
+
)
|
|
86
|
+
return parser
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def main(args):
|
|
90
|
+
"""
|
|
91
|
+
Main entry point for the describe CLI command.
|
|
92
|
+
|
|
93
|
+
Reads a MMIF file and outputs a JSON summary containing:
|
|
94
|
+
- workflow_id: unique identifier for the source and app sequence
|
|
95
|
+
- stats: view counts, annotation counts (total/per-view/per-type),
|
|
96
|
+
and lists of error/warning/empty view IDs
|
|
97
|
+
- views: map of view IDs to app configurations and profiling data
|
|
98
|
+
|
|
99
|
+
:param args: Parsed command-line arguments
|
|
100
|
+
"""
|
|
101
|
+
output = {}
|
|
102
|
+
# if input is a directory
|
|
103
|
+
if isinstance(args.MMIF_FILE, str) and Path(args.MMIF_FILE).is_dir():
|
|
104
|
+
output = describe_mmif_collection(args.MMIF_FILE)
|
|
105
|
+
# if input is a file or stdin
|
|
106
|
+
else:
|
|
107
|
+
# Read MMIF content
|
|
108
|
+
if hasattr(args.MMIF_FILE, 'read'):
|
|
109
|
+
mmif_content = args.MMIF_FILE.read()
|
|
110
|
+
else:
|
|
111
|
+
with open(args.MMIF_FILE, 'r') as f:
|
|
112
|
+
mmif_content = f.read()
|
|
113
|
+
|
|
114
|
+
# For file input, we need to handle the path
|
|
115
|
+
# If input is from stdin, create a temp file
|
|
116
|
+
import tempfile
|
|
117
|
+
tmp_path = None
|
|
118
|
+
try:
|
|
119
|
+
with tempfile.NamedTemporaryFile(
|
|
120
|
+
mode='w', suffix='.mmif', delete=False
|
|
121
|
+
) as tmp:
|
|
122
|
+
tmp.write(mmif_content)
|
|
123
|
+
tmp_path = Path(tmp.name)
|
|
124
|
+
output = describe_single_mmif(tmp_path)
|
|
125
|
+
finally:
|
|
126
|
+
if tmp_path and tmp_path.exists():
|
|
127
|
+
tmp_path.unlink()
|
|
128
|
+
|
|
129
|
+
if output:
|
|
130
|
+
if args.pretty:
|
|
131
|
+
json.dump(output, args.output, indent=2)
|
|
132
|
+
else:
|
|
133
|
+
json.dump(output, args.output)
|
|
134
|
+
args.output.write('\n')
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
parser = prep_argparser()
|
|
139
|
+
args = parser.parse_args()
|
|
140
|
+
main(args)
|
|
@@ -3,26 +3,26 @@ import sys
|
|
|
3
3
|
import textwrap
|
|
4
4
|
|
|
5
5
|
import mmif
|
|
6
|
+
from mmif.utils.workflow_helper import group_views_by_app
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
def prompt_user(mmif_obj: mmif.Mmif) -> int:
|
|
9
10
|
"""
|
|
10
11
|
Function to ask user to choose the rewind range.
|
|
11
12
|
"""
|
|
13
|
+
grouped_apps = group_views_by_app(mmif_obj.views)
|
|
14
|
+
view_to_app_num = {}
|
|
15
|
+
for i, execution in enumerate(grouped_apps):
|
|
16
|
+
for view in execution:
|
|
17
|
+
view_to_app_num[view.id] = i + 1
|
|
12
18
|
|
|
13
|
-
## Give a user options (#, "app", "timestamp") - time order
|
|
14
|
-
n = len(mmif_obj.views)
|
|
15
|
-
i = 0 # option number
|
|
16
|
-
aname = ""
|
|
17
|
-
a = 0
|
|
18
19
|
# header
|
|
19
20
|
print("\n" + "{:<8} {:<8} {:<30} {:<100}".format("view-num", "app-num", "timestamp", "app"))
|
|
21
|
+
view_num = 0
|
|
20
22
|
for view in reversed(mmif_obj.views):
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
i += 1
|
|
25
|
-
print("{:<8} {:<8} {:<30} {:<100}".format(i, a, str(view.metadata.timestamp), str(view.metadata.app)))
|
|
23
|
+
view_num += 1
|
|
24
|
+
app_exec_num = view_to_app_num.get(view.id, 'N/A')
|
|
25
|
+
print("{:<8} {:<15} {:<30} {:<100}".format(view_num, app_exec_num, str(view.metadata.timestamp), str(view.metadata.app)))
|
|
26
26
|
|
|
27
27
|
## User input
|
|
28
28
|
return int(input("\nEnter the number to delete from that point by rewinding: "))
|
|
@@ -33,7 +33,7 @@ def rewind_mmif(mmif_obj: mmif.Mmif, choice: int, choice_is_viewnum: bool = True
|
|
|
33
33
|
Rewind MMIF by deleting the last N views.
|
|
34
34
|
The number of views to rewind is given as a number of "views", or number of "producer apps".
|
|
35
35
|
By default, the number argument is interpreted as the number of "views".
|
|
36
|
-
Note that when the same app is repeatedly run in a CLAMS
|
|
36
|
+
Note that when the same app is repeatedly run in a CLAMS workflow and produces multiple views in a row,
|
|
37
37
|
rewinding in "app" mode will rewind all those views at once.
|
|
38
38
|
|
|
39
39
|
:param mmif_obj: mmif object
|
|
@@ -46,16 +46,9 @@ def rewind_mmif(mmif_obj: mmif.Mmif, choice: int, choice_is_viewnum: bool = True
|
|
|
46
46
|
for vid in list(v.id for v in mmif_obj.views)[-1:-choice-1:-1]:
|
|
47
47
|
mmif_obj.views._items.pop(vid)
|
|
48
48
|
else:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
vid_to_pop = []
|
|
52
|
-
for v in reversed(mmif_obj.views):
|
|
53
|
-
vid_to_pop.append(v.id)
|
|
54
|
-
if app_count >= choice:
|
|
55
|
-
break
|
|
56
|
-
if v.metadata.app != cur_app:
|
|
57
|
-
app_count += 1
|
|
58
|
-
cur_app = v.metadata.app
|
|
49
|
+
grouped_apps = group_views_by_app(mmif_obj.views)
|
|
50
|
+
executions_to_rewind = grouped_apps[-choice:]
|
|
51
|
+
vid_to_pop = [view.id for execution in executions_to_rewind for view in execution]
|
|
59
52
|
for vid in vid_to_pop:
|
|
60
53
|
mmif_obj.views._items.pop(vid)
|
|
61
54
|
return mmif_obj
|
|
@@ -66,7 +59,7 @@ def describe_argparser():
|
|
|
66
59
|
returns two strings: one-line description of the argparser, and addition material,
|
|
67
60
|
which will be shown in `clams --help` and `clams <subcmd> --help`, respectively.
|
|
68
61
|
"""
|
|
69
|
-
oneliner = 'provides CLI to rewind a MMIF from a CLAMS
|
|
62
|
+
oneliner = 'provides CLI to rewind a MMIF from a CLAMS workflow.'
|
|
70
63
|
additional = textwrap.dedent("""
|
|
71
64
|
MMIF rewinder rewinds a MMIF by deleting the last N views.
|
|
72
65
|
N can be specified as a number of views, or a number of producer apps. """)
|
|
@@ -233,7 +233,7 @@ def prep_argparser(**kwargs):
|
|
|
233
233
|
name[len('mmif_docloc_'):]: importlib.import_module(name) for _, name, _ in pkgutil.iter_modules() if
|
|
234
234
|
re.match(r'mmif[-_]docloc[-_]', name)
|
|
235
235
|
}
|
|
236
|
-
parser = argparse.ArgumentParser(description=describe_argparser()[1], formatter_class=argparse.
|
|
236
|
+
parser = argparse.ArgumentParser(description=describe_argparser()[1], formatter_class=argparse.RawDescriptionHelpFormatter, **kwargs)
|
|
237
237
|
parser.add_argument(
|
|
238
238
|
'documents',
|
|
239
239
|
default=None,
|