mmif-python 1.0.2__tar.gz → 1.0.7__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.0.2 → mmif-python-1.0.7}/MANIFEST.in +1 -0
- {mmif-python-1.0.2/mmif_python.egg-info → mmif-python-1.0.7}/PKG-INFO +2 -1
- mmif-python-1.0.7/VERSION +1 -0
- mmif-python-1.0.7/mmif/__init__.py +17 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/serialize/annotation.py +25 -5
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/serialize/model.py +1 -5
- mmif-python-1.0.7/mmif/utils/__init__.py +1 -0
- mmif-python-1.0.7/mmif/utils/video_document_helper.py +208 -0
- mmif-python-1.0.7/mmif/ver/__init__.py +2 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7/mmif_python.egg-info}/PKG-INFO +2 -1
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif_python.egg-info/SOURCES.txt +3 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif_python.egg-info/requires.txt +5 -0
- mmif-python-1.0.7/requirements.cv +3 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/setup.py +4 -0
- mmif-python-1.0.2/VERSION +0 -1
- mmif-python-1.0.2/mmif/__init__.py +0 -36
- mmif-python-1.0.2/mmif/ver/__init__.py +0 -2
- {mmif-python-1.0.2 → mmif-python-1.0.7}/LICENSE +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/README.md +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/res/__init__.py +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/res/clams.vocabulary.yaml +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/res/do-not-edit.txt +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/res/mmif.json +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/serialize/__init__.py +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/serialize/mmif.py +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/serialize/view.py +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/ver/do-not-edit.txt +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/vocabulary/__init__.py +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/vocabulary/annotation_types.py +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/vocabulary/base_types.py +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/vocabulary/do-not-edit.txt +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif/vocabulary/document_types.py +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif_python.egg-info/dependency_links.txt +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/mmif_python.egg-info/top_level.txt +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/requirements.txt +0 -0
- {mmif-python-1.0.2 → mmif-python-1.0.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mmif-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
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
|
|
@@ -17,4 +17,5 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
18
|
Requires-Python: >=3.8
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
|
+
Provides-Extra: cv
|
|
20
21
|
Provides-Extra: dev
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.7
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import importlib.resources
|
|
2
|
+
|
|
3
|
+
# DO NOT CHANGE THIS ORDER, important to prevent circular imports
|
|
4
|
+
from mmif.ver import __version__
|
|
5
|
+
from mmif.ver import __specver__
|
|
6
|
+
from mmif.vocabulary import *
|
|
7
|
+
from mmif.serialize import *
|
|
8
|
+
|
|
9
|
+
_res_pkg = 'res'
|
|
10
|
+
_ver_pkg = 'ver'
|
|
11
|
+
_vocabulary_pkg = 'vocabulary'
|
|
12
|
+
_schema_res_name = 'mmif.json'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_mmif_json_schema():
|
|
16
|
+
# TODO (krim @ 7/14/23): use `as_file` after dropping support for Python 3.8
|
|
17
|
+
return importlib.resources.read_text(f'{__package__}.{_res_pkg}', _schema_res_name)
|
|
@@ -8,6 +8,7 @@ of a view. For documentation on how views are represented, see
|
|
|
8
8
|
"""
|
|
9
9
|
import importlib
|
|
10
10
|
import itertools
|
|
11
|
+
import os
|
|
11
12
|
import pathlib
|
|
12
13
|
import pkgutil
|
|
13
14
|
import re
|
|
@@ -135,6 +136,13 @@ class Annotation(MmifObject):
|
|
|
135
136
|
def __getitem__(self, prop_name: str):
|
|
136
137
|
return self.get(prop_name)
|
|
137
138
|
|
|
139
|
+
def __contains__(self, item):
|
|
140
|
+
try:
|
|
141
|
+
self.get(item)
|
|
142
|
+
return True
|
|
143
|
+
except KeyError:
|
|
144
|
+
return False
|
|
145
|
+
|
|
138
146
|
def is_document(self):
|
|
139
147
|
return isinstance(self.at_type, DocumentTypesBase)
|
|
140
148
|
|
|
@@ -219,7 +227,15 @@ class Document(Annotation):
|
|
|
219
227
|
the three properties in a specific order so that the latest value is
|
|
220
228
|
returned, in case there are multiple values for the same key.
|
|
221
229
|
"""
|
|
222
|
-
if prop_name
|
|
230
|
+
if prop_name == 'id':
|
|
231
|
+
# because all three dicts have `id` key as required field, we need
|
|
232
|
+
# this special case to return the correct value from the correct dict
|
|
233
|
+
return self.id
|
|
234
|
+
elif prop_name == 'location':
|
|
235
|
+
# because location is internally stored in self.location_,
|
|
236
|
+
# it doesn't work with regular __getitem__ method
|
|
237
|
+
return self.location
|
|
238
|
+
elif prop_name in self._props_temporary:
|
|
223
239
|
return self._props_temporary[prop_name]
|
|
224
240
|
elif prop_name in self._props_existing:
|
|
225
241
|
return self._props_existing[prop_name]
|
|
@@ -378,7 +394,7 @@ class DocumentProperties(AnnotationProperties):
|
|
|
378
394
|
if "location_" in serialized:
|
|
379
395
|
serialized["location"] = serialized.pop("location_")
|
|
380
396
|
return serialized
|
|
381
|
-
|
|
397
|
+
|
|
382
398
|
@property
|
|
383
399
|
def text_language(self) -> str:
|
|
384
400
|
return self.text.lang
|
|
@@ -438,7 +454,7 @@ class DocumentProperties(AnnotationProperties):
|
|
|
438
454
|
warnings.warn('location_path() is deprecated. Use location_path_resolved() instead.', DeprecationWarning)
|
|
439
455
|
return self.location_path_resolved()
|
|
440
456
|
|
|
441
|
-
def location_path_resolved(self) -> Optional[str]:
|
|
457
|
+
def location_path_resolved(self, nonexist_ok=True) -> Optional[str]:
|
|
442
458
|
"""
|
|
443
459
|
Retrieves only path name of the document location (hostname is ignored),
|
|
444
460
|
and then try to resolve the path name in the local file system.
|
|
@@ -452,11 +468,15 @@ class DocumentProperties(AnnotationProperties):
|
|
|
452
468
|
return None
|
|
453
469
|
scheme = self.location_scheme()
|
|
454
470
|
if scheme in ('', 'file'):
|
|
455
|
-
|
|
471
|
+
p = urlparse(self.location).path
|
|
456
472
|
elif scheme in discovered_docloc_plugins:
|
|
457
|
-
|
|
473
|
+
p = discovered_docloc_plugins[scheme].resolve(self.location)
|
|
458
474
|
else:
|
|
459
475
|
raise ValueError(f'Cannot resolve location of scheme "{scheme}". Interested in developing mmif-locdoc-{scheme} plugin? See https://clams.ai/mmif-python/plugins')
|
|
476
|
+
if not nonexist_ok and not os.path.exists(p):
|
|
477
|
+
raise FileNotFoundError(f'Cannot find file "{p}"')
|
|
478
|
+
else:
|
|
479
|
+
return p
|
|
460
480
|
|
|
461
481
|
def location_path_literal(self) -> Optional[str]:
|
|
462
482
|
"""
|
|
@@ -11,15 +11,13 @@ core functionality for deserializing MMIF JSON data into live objects
|
|
|
11
11
|
and serializing live objects into MMIF JSON data. Specialized behavior
|
|
12
12
|
for the different components of MMIF is added in the subclasses.
|
|
13
13
|
"""
|
|
14
|
+
|
|
14
15
|
import json
|
|
15
16
|
from datetime import datetime
|
|
16
|
-
from types import MethodType
|
|
17
17
|
from typing import Union, Any, Dict, Optional, TypeVar, Generic, Generator, Iterator, Type, Set
|
|
18
18
|
|
|
19
19
|
from deepdiff import DeepDiff
|
|
20
20
|
|
|
21
|
-
import mmif
|
|
22
|
-
|
|
23
21
|
T = TypeVar('T')
|
|
24
22
|
S = TypeVar('S')
|
|
25
23
|
JSON_PRMTV_TYPES: Type = Union[str, int, float, bool, None]
|
|
@@ -105,8 +103,6 @@ class MmifObject(object):
|
|
|
105
103
|
self._unnamed_attributes = {}
|
|
106
104
|
if mmif_obj is not None:
|
|
107
105
|
self.deserialize(mmif_obj)
|
|
108
|
-
for method in mmif.patches[self.__class__]:
|
|
109
|
-
setattr(self, method.__name__, MethodType(method, self))
|
|
110
106
|
|
|
111
107
|
def disallow_additional_properties(self) -> None:
|
|
112
108
|
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from mmif.utils import video_document_helper
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import warnings
|
|
3
|
+
from typing import List, Union, Tuple
|
|
4
|
+
|
|
5
|
+
import mmif
|
|
6
|
+
from mmif import Annotation, Document, Mmif
|
|
7
|
+
from mmif.vocabulary import DocumentTypes
|
|
8
|
+
|
|
9
|
+
for cv_dep in ('cv2', 'ffmpeg', 'PIL'):
|
|
10
|
+
try:
|
|
11
|
+
importlib.__import__(cv_dep)
|
|
12
|
+
except ImportError as e:
|
|
13
|
+
warnings.warn(f"Optional package \"{e.name}\" is not found. "
|
|
14
|
+
f"You might want to install Computer-Vision dependencies "
|
|
15
|
+
f"by running `pip install mmif-python[cv]=={mmif.__version__}`")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
FPS_DOCPROP_KEY = 'fps'
|
|
19
|
+
DURATION_DOCPROP_KEY = 'duration'
|
|
20
|
+
DURATIONUNIT_DOCPROP_KEY = 'durationTimeUnit'
|
|
21
|
+
|
|
22
|
+
UNIT_NORMALIZATION = {
|
|
23
|
+
'm': 'millisecond',
|
|
24
|
+
'ms': 'millisecond',
|
|
25
|
+
'msec': 'millisecond',
|
|
26
|
+
'millisecond': 'millisecond',
|
|
27
|
+
'milliseconds': 'millisecond',
|
|
28
|
+
's': 'second',
|
|
29
|
+
'se': 'second',
|
|
30
|
+
'sec': 'second',
|
|
31
|
+
'second': 'second',
|
|
32
|
+
'seconds': 'second',
|
|
33
|
+
'f': 'frame',
|
|
34
|
+
'fr': 'frame',
|
|
35
|
+
'frame': 'frame',
|
|
36
|
+
'frames': 'frame',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def capture(vd: Document):
|
|
41
|
+
import cv2 # pytype: disable=import-error
|
|
42
|
+
if vd is None or vd.at_type != DocumentTypes.VideoDocument:
|
|
43
|
+
raise ValueError(f'The document does not exist.')
|
|
44
|
+
|
|
45
|
+
v = cv2.VideoCapture(vd.location_path())
|
|
46
|
+
vd.add_property(FPS_DOCPROP_KEY, v.get(cv2.CAP_PROP_FPS))
|
|
47
|
+
vd.add_property(DURATION_DOCPROP_KEY, v.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
48
|
+
vd.add_property(DURATIONUNIT_DOCPROP_KEY, 'frames')
|
|
49
|
+
return v
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_framerate(vd: Document) -> float:
|
|
53
|
+
if vd is None or vd.at_type != DocumentTypes.VideoDocument:
|
|
54
|
+
raise ValueError(f'The document does not exist.')
|
|
55
|
+
|
|
56
|
+
framerate_keys = (FPS_DOCPROP_KEY, 'framerate')
|
|
57
|
+
for k in framerate_keys:
|
|
58
|
+
if k in vd:
|
|
59
|
+
fps = vd.get_property(k)
|
|
60
|
+
return fps
|
|
61
|
+
capture(vd)
|
|
62
|
+
return vd.get_property(FPS_DOCPROP_KEY)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def extract_frames_as_images(vd: Document, framenums: List[int], as_PIL: bool = False):
|
|
66
|
+
"""
|
|
67
|
+
Extracts frames from a video document as a list of numpy arrays.
|
|
68
|
+
Use `sample_frames` function in this module to get the list of frame numbers first.
|
|
69
|
+
|
|
70
|
+
:param vd: VideoDocument object that holds the video file location
|
|
71
|
+
:param framenums: integers representing the frame numbers to extract
|
|
72
|
+
:param as_PIL: use PIL.Image instead of numpy.ndarray
|
|
73
|
+
:return: frames as a list of numpy arrays or PIL.Image objects
|
|
74
|
+
"""
|
|
75
|
+
import cv2 # pytype: disable=import-error
|
|
76
|
+
if as_PIL:
|
|
77
|
+
from PIL import Image
|
|
78
|
+
frames = []
|
|
79
|
+
video = capture(vd)
|
|
80
|
+
for framenum in framenums:
|
|
81
|
+
video.set(cv2.CAP_PROP_POS_FRAMES, framenum)
|
|
82
|
+
ret, frame = video.read()
|
|
83
|
+
if ret:
|
|
84
|
+
frames.append(Image.fromarray(frame[:, :, ::-1]) if as_PIL else frame)
|
|
85
|
+
else:
|
|
86
|
+
break
|
|
87
|
+
return frames
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_mid_framenum(mmif: Mmif, tf: Annotation):
|
|
91
|
+
"""
|
|
92
|
+
Extracts the middle frame from a video document
|
|
93
|
+
"""
|
|
94
|
+
timeunit = get_annotation_property(mmif, tf, 'timeUnit')
|
|
95
|
+
vd = mmif[get_annotation_property(mmif, tf, 'document')]
|
|
96
|
+
fps = get_framerate(vd)
|
|
97
|
+
return sum(convert(float(tf.get_property(timepoint_propkey)), timeunit, 'frame', fps) for timepoint_propkey in ('start', 'end')) // 2
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def extract_mid_frame(mmif: Mmif, tf: Annotation, as_PIL: bool = False):
|
|
101
|
+
vd = mmif[get_annotation_property(mmif, tf, 'document')]
|
|
102
|
+
return extract_frames_as_images(vd, [get_mid_framenum(mmif, tf)], as_PIL=as_PIL)[0]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def sample_frames(start_frame: int, end_frame: int, sample_ratio: int = 1) -> List[int]:
|
|
106
|
+
"""
|
|
107
|
+
Helper function to sample frames from a time interval.
|
|
108
|
+
When start_frame is 0 and end_frame is X, this function basically works as "cutoff".
|
|
109
|
+
|
|
110
|
+
:param start_frame: start frame of the interval
|
|
111
|
+
:param end_frame: end frame of the interval
|
|
112
|
+
:param sample_ratio: sample ratio or sample step, default is 1, meaning all consecutive frames are sampled
|
|
113
|
+
"""
|
|
114
|
+
sample_ratio = int(sample_ratio)
|
|
115
|
+
if sample_ratio < 1:
|
|
116
|
+
raise ValueError(f"Sample ratio must be greater than 1, but got {sample_ratio}")
|
|
117
|
+
frame_nums: List[int] = []
|
|
118
|
+
for i in range(start_frame, end_frame, sample_ratio):
|
|
119
|
+
frame_nums.append(i)
|
|
120
|
+
return frame_nums
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def convert(time: Union[int, float], in_unit: str, out_unit: str, fps: float) -> Union[int, float]:
|
|
124
|
+
try:
|
|
125
|
+
in_unit = UNIT_NORMALIZATION[in_unit]
|
|
126
|
+
except KeyError:
|
|
127
|
+
raise ValueError(f"Not supported time unit: {in_unit}")
|
|
128
|
+
try:
|
|
129
|
+
out_unit = UNIT_NORMALIZATION[out_unit]
|
|
130
|
+
except KeyError:
|
|
131
|
+
raise ValueError(f"Not supported time unit: {out_unit}")
|
|
132
|
+
# s>s, ms>ms, f>f
|
|
133
|
+
if in_unit == out_unit:
|
|
134
|
+
return time
|
|
135
|
+
elif out_unit == 'frame':
|
|
136
|
+
# ms>f
|
|
137
|
+
if 'millisecond' == in_unit:
|
|
138
|
+
return int(time / 1000 * fps)
|
|
139
|
+
# s>f
|
|
140
|
+
elif 'second' == in_unit:
|
|
141
|
+
return int(time * fps)
|
|
142
|
+
# s>ms
|
|
143
|
+
elif in_unit == 'second':
|
|
144
|
+
return time * 1000
|
|
145
|
+
# ms>s
|
|
146
|
+
elif in_unit == 'millisecond':
|
|
147
|
+
return time // 1000
|
|
148
|
+
# f>ms, f>s
|
|
149
|
+
else:
|
|
150
|
+
return (time / fps) if out_unit == 'second' else (time / fps * 1000) # pytype: disable=bad-return-type
|
|
151
|
+
|
|
152
|
+
def get_annotation_property(mmif, annotation, prop_name):
|
|
153
|
+
# TODO (krim @ 7/18/23): this probably should be merged to the main mmif.serialize packge
|
|
154
|
+
if prop_name in annotation:
|
|
155
|
+
return annotation.get_property(prop_name)
|
|
156
|
+
try:
|
|
157
|
+
return mmif[annotation.parent].metadata.contains[annotation.at_type][prop_name]
|
|
158
|
+
except KeyError:
|
|
159
|
+
raise KeyError(f"Annotation {annotation.id} does not have {prop_name} property.")
|
|
160
|
+
|
|
161
|
+
def convert_timepoint(mmif: Mmif, timepoint: Annotation, out_unit: str) -> Union[int, float]:
|
|
162
|
+
"""
|
|
163
|
+
Converts a time point included in an annotation to a different time unit.
|
|
164
|
+
The input annotation must have ``timePoint`` property.
|
|
165
|
+
|
|
166
|
+
:param mmif: input MMIF to obtain fps and input timeunit
|
|
167
|
+
:param timepoint: annotation with ``timePoint`` property
|
|
168
|
+
:param out_unit: time unit to which the point is converted
|
|
169
|
+
:return: frame number (integer) or second/millisecond (float) of input timepoint
|
|
170
|
+
"""
|
|
171
|
+
in_unit = get_annotation_property(mmif, timepoint, 'timeUnit')
|
|
172
|
+
vd = mmif[get_annotation_property(mmif, timepoint, 'document')]
|
|
173
|
+
return convert(timepoint.get_property('timePoint'), in_unit, out_unit, get_framerate(vd))
|
|
174
|
+
|
|
175
|
+
def convert_timeframe(mmif: Mmif, timeframe: Annotation, out_unit: str) -> Union[Tuple[int, int], Tuple[float, float]]:
|
|
176
|
+
"""
|
|
177
|
+
Converts start and end points in a TimeFrame annotation a different time unit.
|
|
178
|
+
|
|
179
|
+
:param mmif: input MMIF to obtain fps and input timeunit
|
|
180
|
+
:param timeframe: ``TimeFrame` type annotation
|
|
181
|
+
:param out_unit: time unit to which the point is converted
|
|
182
|
+
:return: tuple of frame numbers (integer) or seconds/milliseconds (float) of input start and end
|
|
183
|
+
"""
|
|
184
|
+
in_unit = get_annotation_property(mmif, timeframe, 'timeUnit')
|
|
185
|
+
vd = mmif[get_annotation_property(mmif, timeframe, 'document')]
|
|
186
|
+
return convert(timeframe.get_property('start'), in_unit, out_unit, get_framerate(vd)), \
|
|
187
|
+
convert(timeframe.get_property('end'), in_unit, out_unit, get_framerate(vd))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def framenum_to_second(video_doc: Document, frame: int):
|
|
192
|
+
fps = get_framerate(video_doc)
|
|
193
|
+
return convert(frame, 'f', 's', fps)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def framenum_to_millisecond(video_doc: Document, frame: int):
|
|
197
|
+
fps = get_framerate(video_doc)
|
|
198
|
+
return convert(frame, 'f', 'ms', fps)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def second_to_framenum(video_doc: Document, second) -> int:
|
|
202
|
+
fps = get_framerate(video_doc)
|
|
203
|
+
return int(convert(second, 's', 'f', fps))
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def millisecond_to_framenum(video_doc: Document, millisecond: float) -> int:
|
|
207
|
+
fps = get_framerate(video_doc)
|
|
208
|
+
return int(convert(millisecond, 'ms', 'f', fps))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mmif-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
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
|
|
@@ -17,4 +17,5 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
18
|
Requires-Python: >=3.8
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
|
+
Provides-Extra: cv
|
|
20
21
|
Provides-Extra: dev
|
|
@@ -3,6 +3,7 @@ MANIFEST.in
|
|
|
3
3
|
README.md
|
|
4
4
|
setup.py
|
|
5
5
|
./VERSION
|
|
6
|
+
./requirements.cv
|
|
6
7
|
./requirements.txt
|
|
7
8
|
mmif/__init__.py
|
|
8
9
|
mmif/res/__init__.py
|
|
@@ -14,6 +15,8 @@ mmif/serialize/annotation.py
|
|
|
14
15
|
mmif/serialize/mmif.py
|
|
15
16
|
mmif/serialize/model.py
|
|
16
17
|
mmif/serialize/view.py
|
|
18
|
+
mmif/utils/__init__.py
|
|
19
|
+
mmif/utils/video_document_helper.py
|
|
17
20
|
mmif/ver/__init__.py
|
|
18
21
|
mmif/ver/do-not-edit.txt
|
|
19
22
|
mmif/vocabulary/__init__.py
|
|
@@ -269,6 +269,9 @@ with open('README.md') as readme:
|
|
|
269
269
|
with open('requirements.txt') as requirements:
|
|
270
270
|
requires = requirements.readlines()
|
|
271
271
|
|
|
272
|
+
with open('requirements.cv') as requirements:
|
|
273
|
+
cv_requires = requirements.readlines()
|
|
274
|
+
|
|
272
275
|
setuptools.setup(
|
|
273
276
|
name=name,
|
|
274
277
|
version=version,
|
|
@@ -287,6 +290,7 @@ setuptools.setup(
|
|
|
287
290
|
},
|
|
288
291
|
install_requires=requires,
|
|
289
292
|
extras_require={
|
|
293
|
+
'cv': cv_requires,
|
|
290
294
|
'dev': [
|
|
291
295
|
'pytest',
|
|
292
296
|
'pytest-pep8',
|
mmif-python-1.0.2/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.0.2
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import importlib
|
|
2
|
-
import pkgutil
|
|
3
|
-
import re
|
|
4
|
-
from collections import defaultdict
|
|
5
|
-
from typing import Dict, Type, Callable, Set
|
|
6
|
-
|
|
7
|
-
import pkg_resources
|
|
8
|
-
|
|
9
|
-
# DO NOT CHANGE THIS ORDER, important to prevent circular imports
|
|
10
|
-
from mmif.ver import __version__
|
|
11
|
-
from mmif.ver import __specver__
|
|
12
|
-
from mmif.vocabulary import *
|
|
13
|
-
from mmif.serialize import *
|
|
14
|
-
|
|
15
|
-
_res_pkg = 'res'
|
|
16
|
-
_ver_pkg = 'ver'
|
|
17
|
-
_vocabulary_pkg = 'vocabulary'
|
|
18
|
-
_schema_res_name = 'mmif.json'
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def get_mmif_json_schema():
|
|
22
|
-
res = pkg_resources.resource_stream(f'{__name__}.{_res_pkg}', _schema_res_name)
|
|
23
|
-
res_str = res.read().decode('utf-8')
|
|
24
|
-
res.close()
|
|
25
|
-
return res_str
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
patches: Dict[Type, Set[Callable]] = defaultdict(set)
|
|
29
|
-
for _, name, ispkg in pkgutil.iter_modules():
|
|
30
|
-
if ispkg and re.match(r'mmif[-_]utils[-_]', name):
|
|
31
|
-
mod = importlib.import_module(name)
|
|
32
|
-
for c, ms in mod.patches.items():
|
|
33
|
-
for m in ms:
|
|
34
|
-
if m in patches[c]:
|
|
35
|
-
raise ValueError(f'Patch for {c}::{m.__name__} already exists.')
|
|
36
|
-
patches[c].add(m)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|