clams-python 1.1.5__tar.gz → 1.2.0__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.
- {clams-python-1.1.5/clams_python.egg-info → clams-python-1.2.0}/PKG-INFO +2 -2
- clams-python-1.2.0/VERSION +1 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/app/__init__.py +3 -9
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/mmif_utils/source.py +32 -75
- clams-python-1.2.0/clams/ver/__init__.py +1 -0
- {clams-python-1.1.5 → clams-python-1.2.0/clams_python.egg-info}/PKG-INFO +2 -2
- {clams-python-1.1.5 → clams-python-1.2.0}/clams_python.egg-info/requires.txt +1 -1
- {clams-python-1.1.5 → clams-python-1.2.0}/requirements.txt +1 -1
- {clams-python-1.1.5 → clams-python-1.2.0}/tests/test_clamsapp.py +20 -1
- {clams-python-1.1.5 → clams-python-1.2.0}/tests/test_clamscli.py +5 -0
- clams-python-1.1.5/VERSION +0 -1
- clams-python-1.1.5/clams/ver/__init__.py +0 -1
- {clams-python-1.1.5 → clams-python-1.2.0}/LICENSE +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/MANIFEST.in +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/README.md +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/__init__.py +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/appmetadata/__init__.py +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/__init__.py +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/.dockerignore.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/.gitignore.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/Containerfile.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/LICENSE.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/README.md.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/app.py.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/metadata.py.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/requirements.txt.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/gha/for-clams-team.md.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/gha/workflows/issue-apps-project.yml.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/gha/workflows/issue-assign.yml.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/gha/workflows/issue-close.yml.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/gha/workflows/publish.yml.template +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/mmif_utils/__init__.py +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/mmif_utils/rewind.py +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/restify/__init__.py +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams/serve/__init__.py +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams_python.egg-info/SOURCES.txt +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams_python.egg-info/dependency_links.txt +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams_python.egg-info/entry_points.txt +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/clams_python.egg-info/top_level.txt +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/setup.cfg +0 -0
- {clams-python-1.1.5 → clams-python-1.2.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: clams-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: A collection of APIs to develop CLAMS app for python
|
|
5
5
|
Home-page: https://clams.ai
|
|
6
6
|
Author: Brandeis Lab for Linguistics and Computation
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
14
14
|
Requires-Python: >=3.8
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: mmif-python==1.0.
|
|
17
|
+
Requires-Dist: mmif-python==1.0.13
|
|
18
18
|
Requires-Dist: Flask>=2
|
|
19
19
|
Requires-Dist: Flask-RESTful>=0.3.9
|
|
20
20
|
Requires-Dist: gunicorn>=20
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.2.0
|
|
@@ -190,7 +190,7 @@ class ClamsApp(ABC):
|
|
|
190
190
|
DeprecationWarning, stacklevel=2)
|
|
191
191
|
return self._refine_params(**runtime_params)
|
|
192
192
|
|
|
193
|
-
def sign_view(self, view: View, runtime_conf:
|
|
193
|
+
def sign_view(self, view: View, runtime_conf: dict) -> None:
|
|
194
194
|
"""
|
|
195
195
|
A method to "sign" a new view that this app creates at the beginning of annotation.
|
|
196
196
|
Signing will populate the view metadata with information and configuration of this app.
|
|
@@ -201,13 +201,6 @@ class ClamsApp(ABC):
|
|
|
201
201
|
:param view: a view to sign
|
|
202
202
|
:param runtime_conf: runtime configuration of the app as k-v pairs
|
|
203
203
|
"""
|
|
204
|
-
# TODO (krim @ 8/2/23): once all devs understood this change, make runtime_conf a required argument
|
|
205
|
-
if runtime_conf is None:
|
|
206
|
-
warnings.warn("`runtime_conf` argument for ClamsApp.sign_view() will "
|
|
207
|
-
"no longer be optional in the future. Please pass `runtime_params` "
|
|
208
|
-
"from _annotate() method.",
|
|
209
|
-
FutureWarning, stacklevel=2)
|
|
210
|
-
return
|
|
211
204
|
view.metadata.app = self.metadata.identifier
|
|
212
205
|
if self._RAW_PARAMS_KEY in runtime_conf:
|
|
213
206
|
for k, v in runtime_conf.items():
|
|
@@ -217,7 +210,8 @@ class ClamsApp(ABC):
|
|
|
217
210
|
view.metadata.add_parameter(orik, str(oriv))
|
|
218
211
|
else:
|
|
219
212
|
view.metadata.add_parameter(orik, oriv[0])
|
|
220
|
-
|
|
213
|
+
else:
|
|
214
|
+
view.metadata.add_app_configuration(k, v)
|
|
221
215
|
else:
|
|
222
216
|
# meaning the parameters directly from flask or argparser and values are in lists
|
|
223
217
|
for k, v in runtime_conf.items():
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import itertools
|
|
3
3
|
import json
|
|
4
|
+
import pathlib
|
|
4
5
|
import sys
|
|
5
6
|
import textwrap
|
|
6
|
-
from os import path
|
|
7
7
|
from typing import Union, Generator, List, Optional, Iterable
|
|
8
8
|
from urllib.parse import urlparse
|
|
9
9
|
|
|
@@ -171,24 +171,18 @@ class WorkflowSource:
|
|
|
171
171
|
yield self.produce()
|
|
172
172
|
|
|
173
173
|
|
|
174
|
-
def generate_source_mmif_from_file(documents, prefix=None, **ignored):
|
|
175
|
-
from string import Template
|
|
174
|
+
def generate_source_mmif_from_file(documents, prefix=None, scheme='file', **ignored):
|
|
176
175
|
at_types = {
|
|
177
176
|
'video': DocumentTypes.VideoDocument,
|
|
178
177
|
'audio': DocumentTypes.AudioDocument,
|
|
179
178
|
'text': DocumentTypes.TextDocument,
|
|
180
179
|
'image': DocumentTypes.ImageDocument
|
|
181
180
|
}
|
|
182
|
-
template = Template('''{
|
|
183
|
-
"@type": "${at_type}",
|
|
184
|
-
"properties": {
|
|
185
|
-
"id": "${aid}",
|
|
186
|
-
"mime": "${mime}",
|
|
187
|
-
"location": "${location}" }
|
|
188
|
-
}''')
|
|
189
181
|
pl = WorkflowSource()
|
|
190
|
-
if prefix
|
|
191
|
-
|
|
182
|
+
if prefix:
|
|
183
|
+
prefix = pathlib.PurePosixPath(prefix)
|
|
184
|
+
if not prefix.is_absolute():
|
|
185
|
+
raise ValueError(f"prefix must be an absolute path; given \"{prefix}\".")
|
|
192
186
|
for doc_id, arg in enumerate(documents, start=1):
|
|
193
187
|
arg = arg.strip()
|
|
194
188
|
if len(arg) < 1:
|
|
@@ -200,57 +194,20 @@ def generate_source_mmif_from_file(documents, prefix=None, **ignored):
|
|
|
200
194
|
raise ValueError(
|
|
201
195
|
f'Invalid MIME types, or no MIME type and/or path provided, in argument {doc_id-1} to source'
|
|
202
196
|
)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def generate_source_mmif_from_customscheme(documents, scheme, **ignored):
|
|
220
|
-
from string import Template
|
|
221
|
-
at_types = {
|
|
222
|
-
'video': DocumentTypes.VideoDocument,
|
|
223
|
-
'audio': DocumentTypes.AudioDocument,
|
|
224
|
-
'text': DocumentTypes.TextDocument,
|
|
225
|
-
'image': DocumentTypes.ImageDocument
|
|
226
|
-
}
|
|
227
|
-
template = Template('''{
|
|
228
|
-
"@type": "${at_type}",
|
|
229
|
-
"properties": {
|
|
230
|
-
"id": "${aid}",
|
|
231
|
-
"mime": "${mime}",
|
|
232
|
-
"location": "${location}" }
|
|
233
|
-
}''')
|
|
234
|
-
pl = WorkflowSource()
|
|
235
|
-
for doc_id, arg in enumerate(documents, start=1):
|
|
236
|
-
arg = arg.strip()
|
|
237
|
-
if len(arg) < 1:
|
|
238
|
-
continue
|
|
239
|
-
result = arg.split(':', maxsplit=1)
|
|
240
|
-
if len(result) == 2 and result[0].split('/', maxsplit=1)[0] in at_types:
|
|
241
|
-
mime, location = result
|
|
242
|
-
else:
|
|
243
|
-
raise ValueError(
|
|
244
|
-
f'Invalid MIME types, or no MIME type and/or path provided, in argument {doc_id-1} to source'
|
|
245
|
-
)
|
|
246
|
-
if urlparse(location).scheme == '':
|
|
247
|
-
location = scheme + '://' + location
|
|
248
|
-
doc = template.substitute(
|
|
249
|
-
at_type=str(at_types[mime.split('/', maxsplit=1)[0]]),
|
|
250
|
-
aid=f'd{doc_id}',
|
|
251
|
-
mime=mime,
|
|
252
|
-
location=location
|
|
253
|
-
)
|
|
197
|
+
location_uri = urlparse(location, scheme=scheme)
|
|
198
|
+
if location_uri.scheme == 'file':
|
|
199
|
+
location = pathlib.PurePosixPath(location_uri.path)
|
|
200
|
+
if prefix and location.is_absolute():
|
|
201
|
+
raise ValueError(f"when prefix is used, file location must not be an absolute path; given \"{location}\".")
|
|
202
|
+
elif not prefix and not location.is_absolute():
|
|
203
|
+
raise ValueError(f'file location must be an absolute path, or --prefix must be used; given \"{location}\".')
|
|
204
|
+
elif prefix and not location.is_absolute():
|
|
205
|
+
location = prefix / location
|
|
206
|
+
doc = Document()
|
|
207
|
+
doc.at_type = at_types[mime.split('/', maxsplit=1)[0]]
|
|
208
|
+
doc.properties.location = f"{location_uri.scheme}://{location}"
|
|
209
|
+
doc.properties.id = f'd{doc_id}'
|
|
210
|
+
doc.properties.mime = mime
|
|
254
211
|
pl.add_document(doc)
|
|
255
212
|
return pl.produce().serialize(pretty=True)
|
|
256
213
|
|
|
@@ -274,19 +231,22 @@ def prep_argparser(**kwargs):
|
|
|
274
231
|
default=None,
|
|
275
232
|
action='store',
|
|
276
233
|
nargs='+',
|
|
277
|
-
help=
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
234
|
+
help='This list of documents MUST be colon-delimited pairs of document types and file locations. A document '
|
|
235
|
+
'type can be one of `audio`, `video`, `text`, `image`, or a MIME type string (such as video/mp4). The '
|
|
236
|
+
'file locations MUST be valid URI strings (e.g. `file:///path/to/file.mp4`, or URI scheme part can be '
|
|
237
|
+
'omitted, when `--scheme` flag is used). Note that when `file://` scheme is used (default), locations '
|
|
238
|
+
'MUST BE POSIX forms (Windows forms are not supported). The output will be a MMIF file containing a '
|
|
239
|
+
'document for each of those file paths, with the appropriate ``@type`` and MIME type (if given).'
|
|
281
240
|
)
|
|
282
241
|
parser.add_argument(
|
|
283
242
|
'-p', '--prefix',
|
|
284
243
|
default=None,
|
|
285
244
|
metavar='PATH',
|
|
286
245
|
nargs='?',
|
|
287
|
-
help='An absolute path to use as prefix for file paths (ONLY WORKS with `file
|
|
288
|
-
'
|
|
289
|
-
'
|
|
246
|
+
help='An absolute path to use as prefix for file paths (ONLY WORKS with the default `file://` scheme, ignored '
|
|
247
|
+
'otherwise. MUST BE a POSIX form, Windows form is not supported). If prefix is set, document file paths '
|
|
248
|
+
'MUST be relative. Useful when creating source MMIF files from a system that\'s different from the '
|
|
249
|
+
'environment that actually runs the workflow (e.g. in a container).'
|
|
290
250
|
)
|
|
291
251
|
parser.add_argument(
|
|
292
252
|
'-o', '--output',
|
|
@@ -300,7 +260,7 @@ def prep_argparser(**kwargs):
|
|
|
300
260
|
default='file',
|
|
301
261
|
action='store',
|
|
302
262
|
nargs='?',
|
|
303
|
-
help='A scheme to associate with the document location URI. When not given, the default scheme is `file
|
|
263
|
+
help='A scheme to associate with the document location URI. When not given, the default scheme is `file://`.'
|
|
304
264
|
)
|
|
305
265
|
return parser
|
|
306
266
|
|
|
@@ -310,10 +270,7 @@ def main(args):
|
|
|
310
270
|
out_f = open(args.output, 'w')
|
|
311
271
|
else:
|
|
312
272
|
out_f = sys.stdout
|
|
313
|
-
|
|
314
|
-
mmif = generate_source_mmif_from_file(**vars(args))
|
|
315
|
-
else:
|
|
316
|
-
mmif = generate_source_mmif_from_customscheme(**vars(args))
|
|
273
|
+
mmif = generate_source_mmif_from_file(windows_path=False, **vars(args))
|
|
317
274
|
out_f.write(mmif)
|
|
318
275
|
return mmif
|
|
319
276
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.2.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: clams-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: A collection of APIs to develop CLAMS app for python
|
|
5
5
|
Home-page: https://clams.ai
|
|
6
6
|
Author: Brandeis Lab for Linguistics and Computation
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
14
14
|
Requires-Python: >=3.8
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: mmif-python==1.0.
|
|
17
|
+
Requires-Dist: mmif-python==1.0.13
|
|
18
18
|
Requires-Dist: Flask>=2
|
|
19
19
|
Requires-Dist: Flask-RESTful>=0.3.9
|
|
20
20
|
Requires-Dist: gunicorn>=20
|
|
@@ -228,7 +228,26 @@ class TestClamsApp(unittest.TestCase):
|
|
|
228
228
|
in_mmif.metadata.mmif = f"http://mmif.clams.ai/{incompat_ver}"
|
|
229
229
|
with pytest.raises(ValueError):
|
|
230
230
|
self.app.annotate(in_mmif)
|
|
231
|
-
|
|
231
|
+
|
|
232
|
+
def test_sign_view(self):
|
|
233
|
+
m = Mmif(self.in_mmif)
|
|
234
|
+
v1 = m.new_view()
|
|
235
|
+
self.app.sign_view(v1, {})
|
|
236
|
+
self.assertEqual(v1.metadata.app, self.app.metadata.identifier)
|
|
237
|
+
self.assertEqual(len(v1.metadata.parameters), 0)
|
|
238
|
+
v2 = m.new_view()
|
|
239
|
+
raw_query_string_arguments = {'undefined_param1': ['value1']} # values are lists as our restifier uses `to_dict(flat=False)`
|
|
240
|
+
self.app.sign_view(v2, self.app._refine_params(**raw_query_string_arguments))
|
|
241
|
+
self.assertEqual(v2.metadata.app, self.app.metadata.identifier)
|
|
242
|
+
self.assertEqual(len(v2.metadata.parameters), 1)
|
|
243
|
+
self.assertFalse(clams.ClamsApp._RAW_PARAMS_KEY in v2.metadata.appConfiguration)
|
|
244
|
+
for param in self.app.metadata.parameters:
|
|
245
|
+
# any parameter with defaults should be recorded
|
|
246
|
+
if param.default is not None:
|
|
247
|
+
self.assertTrue(param.name in v2.metadata.appConfiguration)
|
|
248
|
+
elif param.name not in raw_query_string_arguments:
|
|
249
|
+
self.assertFalse(param.name in v2.metadata.appConfiguration)
|
|
250
|
+
|
|
232
251
|
def test_annotate(self):
|
|
233
252
|
# The example app is hard-coded to **always** emit version mismatch warning
|
|
234
253
|
out_mmif = self.app.annotate(self.in_mmif)
|
|
@@ -3,6 +3,7 @@ import copy
|
|
|
3
3
|
import io
|
|
4
4
|
import os
|
|
5
5
|
import unittest
|
|
6
|
+
import unittest.mock
|
|
6
7
|
|
|
7
8
|
from mmif.serialize import Mmif
|
|
8
9
|
from mmif.vocabulary import DocumentTypes, AnnotationTypes
|
|
@@ -63,6 +64,10 @@ class TestSource(unittest.TestCase):
|
|
|
63
64
|
with self.assertRaises(ValueError):
|
|
64
65
|
self.generate_source_mmif()
|
|
65
66
|
|
|
67
|
+
@unittest.mock.patch('os.name', 'nt')
|
|
68
|
+
def test_on_windows(self):
|
|
69
|
+
self.test_accept_file_paths()
|
|
70
|
+
|
|
66
71
|
def test_accept_prefixed_file_paths(self):
|
|
67
72
|
self.prefix = '/a/b'
|
|
68
73
|
self.docs.append("video:c.mp4")
|
clams-python-1.1.5/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.1.5
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.1.5"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/.dockerignore.template
RENAMED
|
File without changes
|
|
File without changes
|
{clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/Containerfile.template
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/app/requirements.txt.template
RENAMED
|
File without changes
|
{clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/gha/for-clams-team.md.template
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clams-python-1.1.5 → clams-python-1.2.0}/clams/develop/templates/gha/workflows/publish.yml.template
RENAMED
|
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
|