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.
Files changed (53) hide show
  1. {mmif_python-1.2.0/mmif_python.egg-info → mmif_python-1.2.1}/PKG-INFO +1 -1
  2. mmif_python-1.2.1/VERSION +1 -0
  3. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/annotation.py +1 -1
  4. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/mmif.py +1 -1
  5. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/view.py +1 -1
  6. mmif_python-1.2.1/mmif/utils/cli/describe.py +140 -0
  7. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/cli/rewind.py +15 -22
  8. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/cli/source.py +1 -1
  9. mmif_python-1.2.1/mmif/utils/workflow_helper.py +466 -0
  10. mmif_python-1.2.1/mmif/ver/__init__.py +2 -0
  11. {mmif_python-1.2.0 → mmif_python-1.2.1/mmif_python.egg-info}/PKG-INFO +1 -1
  12. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/SOURCES.txt +1 -0
  13. {mmif_python-1.2.0 → mmif_python-1.2.1}/tests/test_utils.py +63 -0
  14. mmif_python-1.2.1/tests/test_utils_cli.py +306 -0
  15. mmif_python-1.2.0/VERSION +0 -1
  16. mmif_python-1.2.0/mmif/utils/cli/describe.py +0 -333
  17. mmif_python-1.2.0/mmif/ver/__init__.py +0 -2
  18. mmif_python-1.2.0/tests/test_utils_cli.py +0 -170
  19. {mmif_python-1.2.0 → mmif_python-1.2.1}/LICENSE +0 -0
  20. {mmif_python-1.2.0 → mmif_python-1.2.1}/MANIFEST.in +0 -0
  21. {mmif_python-1.2.0 → mmif_python-1.2.1}/README.md +0 -0
  22. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/__init__.py +0 -0
  23. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/res/__init__.py +0 -0
  24. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/res/clams.vocabulary.yaml +0 -0
  25. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/res/do-not-edit.txt +0 -0
  26. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/res/mmif.json +0 -0
  27. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/__init__.py +0 -0
  28. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/serialize/model.py +0 -0
  29. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/__init__.py +0 -0
  30. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/cli/__init__.py +0 -0
  31. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/sequence_helper.py +0 -0
  32. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/text_document_helper.py +0 -0
  33. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/timeunit_helper.py +0 -0
  34. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/utils/video_document_helper.py +0 -0
  35. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/ver/do-not-edit.txt +0 -0
  36. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/__init__.py +0 -0
  37. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/annotation_types.py +0 -0
  38. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/base_types.py +0 -0
  39. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/do-not-edit.txt +0 -0
  40. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif/vocabulary/document_types.py +0 -0
  41. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_docloc_http/__init__.py +0 -0
  42. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/dependency_links.txt +0 -0
  43. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/entry_points.txt +0 -0
  44. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/requires.txt +0 -0
  45. {mmif_python-1.2.0 → mmif_python-1.2.1}/mmif_python.egg-info/top_level.txt +0 -0
  46. {mmif_python-1.2.0 → mmif_python-1.2.1}/requirements.cv +0 -0
  47. {mmif_python-1.2.0 → mmif_python-1.2.1}/requirements.seq +0 -0
  48. {mmif_python-1.2.0 → mmif_python-1.2.1}/requirements.txt +0 -0
  49. {mmif_python-1.2.0 → mmif_python-1.2.1}/setup.cfg +0 -0
  50. {mmif_python-1.2.0 → mmif_python-1.2.1}/setup.py +0 -0
  51. {mmif_python-1.2.0 → mmif_python-1.2.1}/tests/test_serialize.py +0 -0
  52. {mmif_python-1.2.0 → mmif_python-1.2.1}/tests/test_versioncompat.py +0 -0
  53. {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.0
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 pipeline as a part
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 pipeline's running),
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 pipeline that are annotating
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
- if view.metadata.app != aname:
22
- aname = view.metadata.app
23
- a += 1
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 pipeline and produces multiple views in a row,
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
- app_count = 0
50
- cur_app = ""
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 pipeline.'
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.RawTextHelpFormatter, **kwargs)
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,