clams-python 1.2.0__tar.gz → 1.2.2__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.2.0/clams_python.egg-info → clams_python-1.2.2}/PKG-INFO +2 -2
- clams_python-1.2.2/VERSION +1 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/app/__init__.py +28 -7
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/app.py.template +1 -2
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/restify/__init__.py +3 -1
- clams_python-1.2.2/clams/ver/__init__.py +1 -0
- {clams-python-1.2.0 → clams_python-1.2.2/clams_python.egg-info}/PKG-INFO +2 -2
- {clams-python-1.2.0 → clams_python-1.2.2}/clams_python.egg-info/requires.txt +1 -1
- {clams-python-1.2.0 → clams_python-1.2.2}/requirements.txt +1 -1
- {clams-python-1.2.0 → clams_python-1.2.2}/tests/test_clamsapp.py +22 -4
- clams-python-1.2.0/VERSION +0 -1
- clams-python-1.2.0/clams/ver/__init__.py +0 -1
- {clams-python-1.2.0 → clams_python-1.2.2}/LICENSE +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/MANIFEST.in +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/README.md +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/__init__.py +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/appmetadata/__init__.py +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/__init__.py +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/.dockerignore.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/.gitignore.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/Containerfile.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/LICENSE.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/README.md.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/metadata.py.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/requirements.txt.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/gha/for-clams-team.md.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/gha/workflows/issue-apps-project.yml.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/gha/workflows/issue-assign.yml.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/gha/workflows/issue-close.yml.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/gha/workflows/publish.yml.template +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/mmif_utils/__init__.py +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/mmif_utils/rewind.py +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/mmif_utils/source.py +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams/serve/__init__.py +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams_python.egg-info/SOURCES.txt +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams_python.egg-info/dependency_links.txt +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams_python.egg-info/entry_points.txt +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/clams_python.egg-info/top_level.txt +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/setup.cfg +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/setup.py +0 -0
- {clams-python-1.2.0 → clams_python-1.2.2}/tests/test_clamscli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: clams-python
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
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.14
|
|
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.2
|
|
@@ -122,7 +122,9 @@ class ClamsApp(ABC):
|
|
|
122
122
|
if key not in self.annotate_param_spec:
|
|
123
123
|
issued_warnings.append(UserWarning(f'An undefined parameter "{key}" (value: "{runtime_params[key]}") is passed'))
|
|
124
124
|
# this will do casting + refinement altogether
|
|
125
|
+
self.logger.debug(f"User parameters: {runtime_params}")
|
|
125
126
|
refined = self._refine_params(**runtime_params)
|
|
127
|
+
self.logger.debug(f"Refined parameters: {refined}")
|
|
126
128
|
pretty = refined.get('pretty', False)
|
|
127
129
|
with warnings.catch_warnings(record=True) as ws:
|
|
128
130
|
annotated = self._annotate(mmif, **refined)
|
|
@@ -176,7 +178,14 @@ class ClamsApp(ABC):
|
|
|
176
178
|
raise ValueError(f"Value for parameter \"{parameter.name}\" must be one of {parameter.choices}.")
|
|
177
179
|
refined[parameter.name] = casted[parameter.name]
|
|
178
180
|
elif parameter.default is not None:
|
|
179
|
-
|
|
181
|
+
# have to cast the default values as well, since
|
|
182
|
+
# 1. `map` type default values are not actually expected as a map (dict)
|
|
183
|
+
# 2. developers can use data type not matching the spec
|
|
184
|
+
if isinstance(parameter.default, list):
|
|
185
|
+
casted_default = self.annotate_param_caster.cast({parameter.name: list(map(str, parameter.default))})
|
|
186
|
+
else:
|
|
187
|
+
casted_default = self.annotate_param_caster.cast({parameter.name: [str(parameter.default)]})
|
|
188
|
+
refined.update(casted_default)
|
|
180
189
|
else:
|
|
181
190
|
raise ValueError(f"Cannot find configuration for a required parameter \"{parameter.name}\".")
|
|
182
191
|
# raw input params are hidden under a special key
|
|
@@ -202,11 +211,12 @@ class ClamsApp(ABC):
|
|
|
202
211
|
:param runtime_conf: runtime configuration of the app as k-v pairs
|
|
203
212
|
"""
|
|
204
213
|
view.metadata.app = self.metadata.identifier
|
|
214
|
+
params_map = {p.name: p for p in self.metadata.parameters}
|
|
205
215
|
if self._RAW_PARAMS_KEY in runtime_conf:
|
|
206
216
|
for k, v in runtime_conf.items():
|
|
207
217
|
if k == self._RAW_PARAMS_KEY:
|
|
208
218
|
for orik, oriv in v.items():
|
|
209
|
-
if orik in
|
|
219
|
+
if orik in params_map and params_map[orik].multivalued:
|
|
210
220
|
view.metadata.add_parameter(orik, str(oriv))
|
|
211
221
|
else:
|
|
212
222
|
view.metadata.add_parameter(orik, oriv[0])
|
|
@@ -215,7 +225,7 @@ class ClamsApp(ABC):
|
|
|
215
225
|
else:
|
|
216
226
|
# meaning the parameters directly from flask or argparser and values are in lists
|
|
217
227
|
for k, v in runtime_conf.items():
|
|
218
|
-
if k in
|
|
228
|
+
if k in params_map and params_map[k].multivalued:
|
|
219
229
|
view.metadata.add_parameter(k, str(v))
|
|
220
230
|
else:
|
|
221
231
|
view.metadata.add_parameter(k, v[0])
|
|
@@ -335,8 +345,8 @@ class ParameterCaster(object):
|
|
|
335
345
|
assert isinstance(vs, list), f"Expected a list of values for key {k}, but got {vs} of type {type(vs)}"
|
|
336
346
|
assert all(isinstance(v, str) for v in vs), f"Expected a list of strings for key {k}, but got {vs} of types {[type(v) for v in vs]}"
|
|
337
347
|
if k in self.param_spec:
|
|
348
|
+
valuetype, multivalued = self.param_spec[k]
|
|
338
349
|
for v in vs:
|
|
339
|
-
valuetype, multivalued = self.param_spec[k]
|
|
340
350
|
if multivalued or k not in casted: # effectively only keeps the first value for non-multi params
|
|
341
351
|
if valuetype == bool:
|
|
342
352
|
v = self.bool_param(v)
|
|
@@ -355,11 +365,22 @@ class ParameterCaster(object):
|
|
|
355
365
|
casted.setdefault(k, []).append(v)
|
|
356
366
|
else:
|
|
357
367
|
casted[k] = v
|
|
368
|
+
# when an empty value is passed (usually as a default value)
|
|
369
|
+
# just add an empty list or dict as a placeholder
|
|
370
|
+
# explicit check for `len == 0` is required to prevent
|
|
371
|
+
# empty values are set for params that don't have default values
|
|
372
|
+
if multivalued and len(vs) == 0:
|
|
373
|
+
if valuetype == dict:
|
|
374
|
+
casted.setdefault(k, {})
|
|
375
|
+
else:
|
|
376
|
+
casted.setdefault(k, [])
|
|
358
377
|
else:
|
|
359
|
-
if
|
|
360
|
-
|
|
361
|
-
|
|
378
|
+
# if the parameter is not defined in the spec, there's no easy way to figure out
|
|
379
|
+
# the user's intention whether it should be a list (multivalued) or a single value.
|
|
380
|
+
if len(vs) == 1:
|
|
362
381
|
casted[k] = vs[0]
|
|
382
|
+
else:
|
|
383
|
+
casted[k] = vs
|
|
363
384
|
return casted # pytype: disable=bad-return-type
|
|
364
385
|
|
|
365
386
|
@staticmethod
|
|
@@ -13,7 +13,6 @@ The app.py script does several things:
|
|
|
13
13
|
|
|
14
14
|
import argparse
|
|
15
15
|
import logging
|
|
16
|
-
from typing import Union
|
|
17
16
|
|
|
18
17
|
# Imports needed for Clams and MMIF.
|
|
19
18
|
# Non-NLP Clams applications will require AnnotationTypes
|
|
@@ -36,7 +35,7 @@ class $APP_CLASS_NAME(ClamsApp):
|
|
|
36
35
|
# When using the ``metadata.py`` leave this do-nothing "pass" method here.
|
|
37
36
|
pass
|
|
38
37
|
|
|
39
|
-
def _annotate(self, mmif:
|
|
38
|
+
def _annotate(self, mmif: Mmif, **parameters) -> Mmif:
|
|
40
39
|
# see https://sdk.clams.ai/autodoc/clams.app.html#clams.app.ClamsApp._annotate
|
|
41
40
|
raise NotImplementedError
|
|
42
41
|
|
|
@@ -124,7 +124,9 @@ class ClamsHTTPApi(Resource):
|
|
|
124
124
|
|
|
125
125
|
:return: Returns app metadata in a HTTP response.
|
|
126
126
|
"""
|
|
127
|
-
|
|
127
|
+
# this will catch duplicate arguments with different values into a list under the key
|
|
128
|
+
raw_params = request.args.to_dict(flat=False)
|
|
129
|
+
return self.json_to_response(self.cla.appmetadata(**raw_params))
|
|
128
130
|
|
|
129
131
|
def post(self) -> Response:
|
|
130
132
|
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.2.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: clams-python
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
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.14
|
|
18
18
|
Requires-Dist: Flask>=2
|
|
19
19
|
Requires-Dist: Flask-RESTful>=0.3.9
|
|
20
20
|
Requires-Dist: gunicorn>=20
|
|
@@ -236,8 +236,8 @@ class TestClamsApp(unittest.TestCase):
|
|
|
236
236
|
self.assertEqual(v1.metadata.app, self.app.metadata.identifier)
|
|
237
237
|
self.assertEqual(len(v1.metadata.parameters), 0)
|
|
238
238
|
v2 = m.new_view()
|
|
239
|
-
|
|
240
|
-
self.app.sign_view(v2, self.app._refine_params(**
|
|
239
|
+
args2 = {'undefined_param1': ['value1']} # values are lists as our restifier uses `to_dict(flat=False)`
|
|
240
|
+
self.app.sign_view(v2, self.app._refine_params(**args2))
|
|
241
241
|
self.assertEqual(v2.metadata.app, self.app.metadata.identifier)
|
|
242
242
|
self.assertEqual(len(v2.metadata.parameters), 1)
|
|
243
243
|
self.assertFalse(clams.ClamsApp._RAW_PARAMS_KEY in v2.metadata.appConfiguration)
|
|
@@ -245,8 +245,22 @@ class TestClamsApp(unittest.TestCase):
|
|
|
245
245
|
# any parameter with defaults should be recorded
|
|
246
246
|
if param.default is not None:
|
|
247
247
|
self.assertTrue(param.name in v2.metadata.appConfiguration)
|
|
248
|
-
elif param.name not in
|
|
248
|
+
elif param.name not in args2:
|
|
249
249
|
self.assertFalse(param.name in v2.metadata.appConfiguration)
|
|
250
|
+
v3 = m.new_view()
|
|
251
|
+
self.app.metadata.add_parameter('multivalued_param', 'dummy parameter with multivalues', type='string', multivalued=True, default=[])
|
|
252
|
+
args3 = {'undefined_param1': ['value1']}
|
|
253
|
+
self.app.sign_view(v3, self.app._refine_params(**args3))
|
|
254
|
+
self.assertEqual(len(v3.metadata.parameters), 1)
|
|
255
|
+
self.assertEqual(len(v3.metadata.appConfiguration), 3) # universal (pretty) + `raise_error` in metadata.py + `multivalued_param`
|
|
256
|
+
self.assertEqual(v3.metadata.appConfiguration['multivalued_param'], [])
|
|
257
|
+
v4 = m.new_view()
|
|
258
|
+
multiple_values = ['value1', 'value2']
|
|
259
|
+
args4 = {'multivalued_param': multiple_values}
|
|
260
|
+
self.app.sign_view(v4, self.app._refine_params(**args4))
|
|
261
|
+
self.assertEqual(len(v4.metadata.parameters), 1)
|
|
262
|
+
self.assertEqual(len(v4.metadata.appConfiguration), 3)
|
|
263
|
+
self.assertEqual(len(v4.metadata.parameters['multivalued_param']), len(str(multiple_values)))
|
|
250
264
|
|
|
251
265
|
def test_annotate(self):
|
|
252
266
|
# The example app is hard-coded to **always** emit version mismatch warning
|
|
@@ -307,6 +321,10 @@ class TestClamsApp(unittest.TestCase):
|
|
|
307
321
|
description='float +def +mv')
|
|
308
322
|
self.app.metadata.add_parameter('param7', type='number', default=[], multivalued=True,
|
|
309
323
|
description='float +def +empty +mv')
|
|
324
|
+
# need to manually rebuild caster object, because the metadata has updated after the app is initialized
|
|
325
|
+
for param_spec in self.app.metadata.parameters:
|
|
326
|
+
self.app.annotate_param_spec[param_spec.name] = (param_spec.type, param_spec.multivalued)
|
|
327
|
+
self.app.annotate_param_caster = ParameterCaster(self.app.annotate_param_spec)
|
|
310
328
|
with self.assertRaises(ValueError):
|
|
311
329
|
self.app._refine_params(**{}) # param1 is required, but not passed
|
|
312
330
|
dummy_params = {'param1': ['okay'], 'non_parameter': ['should be ignored']}
|
|
@@ -375,7 +393,7 @@ class TestRestifier(unittest.TestCase):
|
|
|
375
393
|
def test_can_put_as_json(self):
|
|
376
394
|
put = self.app.put('/', data=ExampleInputMMIF.get_mmif(), headers={"Content-Type": "Application/json"})
|
|
377
395
|
self.assertIsNotNone(put)
|
|
378
|
-
self.assertEqual(put.status_code
|
|
396
|
+
self.assertEqual(200, put.status_code)
|
|
379
397
|
self.assertIsNotNone(Mmif(put.get_data(as_text=True)))
|
|
380
398
|
|
|
381
399
|
def test_can_pass_params(self):
|
clams-python-1.2.0/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.2.0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.2.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/.dockerignore.template
RENAMED
|
File without changes
|
|
File without changes
|
{clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/Containerfile.template
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clams-python-1.2.0 → clams_python-1.2.2}/clams/develop/templates/app/requirements.txt.template
RENAMED
|
File without changes
|
{clams-python-1.2.0 → clams_python-1.2.2}/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.2.0 → clams_python-1.2.2}/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
|
|
File without changes
|