clams-python 1.1.0__tar.gz → 1.1.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.
Files changed (41) hide show
  1. {clams-python-1.1.0/clams_python.egg-info → clams-python-1.1.2}/PKG-INFO +7 -6
  2. {clams-python-1.1.0 → clams-python-1.1.2}/README.md +5 -4
  3. clams-python-1.1.2/VERSION +1 -0
  4. {clams-python-1.1.0 → clams-python-1.1.2}/clams/app/__init__.py +3 -6
  5. {clams-python-1.1.0 → clams-python-1.1.2}/clams/appmetadata/__init__.py +6 -6
  6. {clams-python-1.1.0 → clams-python-1.1.2}/clams/mmif_utils/rewind.py +28 -38
  7. {clams-python-1.1.0 → clams-python-1.1.2}/clams/restify/__init__.py +7 -4
  8. clams-python-1.1.2/clams/ver/__init__.py +1 -0
  9. {clams-python-1.1.0 → clams-python-1.1.2/clams_python.egg-info}/PKG-INFO +7 -6
  10. {clams-python-1.1.0 → clams-python-1.1.2}/clams_python.egg-info/requires.txt +1 -1
  11. {clams-python-1.1.0 → clams-python-1.1.2}/requirements.txt +1 -1
  12. {clams-python-1.1.0 → clams-python-1.1.2}/tests/test_clamsapp.py +17 -6
  13. clams-python-1.1.0/VERSION +0 -1
  14. clams-python-1.1.0/clams/ver/__init__.py +0 -1
  15. {clams-python-1.1.0 → clams-python-1.1.2}/LICENSE +0 -0
  16. {clams-python-1.1.0 → clams-python-1.1.2}/MANIFEST.in +0 -0
  17. {clams-python-1.1.0 → clams-python-1.1.2}/clams/__init__.py +0 -0
  18. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/__init__.py +0 -0
  19. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/app/.dockerignore.template +0 -0
  20. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/app/.gitignore.template +0 -0
  21. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/app/Containerfile.template +0 -0
  22. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/app/LICENSE.template +0 -0
  23. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/app/README.md.template +0 -0
  24. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/app/app.py.template +0 -0
  25. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/app/metadata.py.template +0 -0
  26. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/app/requirements.txt.template +0 -0
  27. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/gha/for-clams-team.md.template +0 -0
  28. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/gha/workflows/issue-apps-project.yml.template +0 -0
  29. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/gha/workflows/issue-assign.yml.template +0 -0
  30. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/gha/workflows/issue-close.yml.template +0 -0
  31. {clams-python-1.1.0 → clams-python-1.1.2}/clams/develop/templates/gha/workflows/publish.yml.template +0 -0
  32. {clams-python-1.1.0 → clams-python-1.1.2}/clams/mmif_utils/__init__.py +0 -0
  33. {clams-python-1.1.0 → clams-python-1.1.2}/clams/mmif_utils/source.py +0 -0
  34. {clams-python-1.1.0 → clams-python-1.1.2}/clams/serve/__init__.py +0 -0
  35. {clams-python-1.1.0 → clams-python-1.1.2}/clams_python.egg-info/SOURCES.txt +0 -0
  36. {clams-python-1.1.0 → clams-python-1.1.2}/clams_python.egg-info/dependency_links.txt +0 -0
  37. {clams-python-1.1.0 → clams-python-1.1.2}/clams_python.egg-info/entry_points.txt +0 -0
  38. {clams-python-1.1.0 → clams-python-1.1.2}/clams_python.egg-info/top_level.txt +0 -0
  39. {clams-python-1.1.0 → clams-python-1.1.2}/setup.cfg +0 -0
  40. {clams-python-1.1.0 → clams-python-1.1.2}/setup.py +0 -0
  41. {clams-python-1.1.0 → clams-python-1.1.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.1.0
3
+ Version: 1.1.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.8
17
+ Requires-Dist: mmif-python==1.0.9
18
18
  Requires-Dist: Flask>=2
19
19
  Requires-Dist: Flask-RESTful>=0.3.9
20
20
  Requires-Dist: gunicorn>=20
@@ -33,9 +33,10 @@ Requires-Dist: jsonschema>=3
33
33
  1. a flask-based wrapper to run a Python CLAMS app as an HTTP web app
34
34
  1. cookie-cutter shell command that sets up everything and starts a new CLAMS app project
35
35
 
36
- ### Start now from [Getting Started](introduction.html)!
36
+ ### Start now from [Getting Started](https://clamsproject.github.io/clams-python/introduction.html)!
37
37
 
38
38
  ## For more ...
39
- For user manuals and Python API documentation, take a look at [Python modules](https://clams.ai/clams-python/modules.html).
40
-
41
- For MMIF-specific Python API documentation, take a look at the [mmif-python website](https://clams.ai/mmif-python).
39
+ * [Version history and patch notes](https://github.com/clamsproject/clams-python/blob/main/CHANGELOG.md)
40
+ * [CLAMS Python API documentation](https://clamsproject.github.io/clams-python/modules.html)
41
+ * [MMIF-specific Python API documentation](https://clamsproject.github.io/mmif-python)
42
+ * [Public CLAMS App Directory](https://clamsproject.github.io/apps)
@@ -9,9 +9,10 @@
9
9
  1. a flask-based wrapper to run a Python CLAMS app as an HTTP web app
10
10
  1. cookie-cutter shell command that sets up everything and starts a new CLAMS app project
11
11
 
12
- ### Start now from [Getting Started](introduction.html)!
12
+ ### Start now from [Getting Started](https://clamsproject.github.io/clams-python/introduction.html)!
13
13
 
14
14
  ## For more ...
15
- For user manuals and Python API documentation, take a look at [Python modules](https://clams.ai/clams-python/modules.html).
16
-
17
- For MMIF-specific Python API documentation, take a look at the [mmif-python website](https://clams.ai/mmif-python).
15
+ * [Version history and patch notes](https://github.com/clamsproject/clams-python/blob/main/CHANGELOG.md)
16
+ * [CLAMS Python API documentation](https://clamsproject.github.io/clams-python/modules.html)
17
+ * [MMIF-specific Python API documentation](https://clamsproject.github.io/mmif-python)
18
+ * [Public CLAMS App Directory](https://clamsproject.github.io/apps)
@@ -0,0 +1 @@
1
+ 1.1.2
@@ -137,7 +137,6 @@ class ClamsApp(ABC):
137
137
 
138
138
  #. Create a new view (or views) by calling :meth:`~mmif.serialize.mmif.Mmif.new_view` on the input mmif object.
139
139
  #. Call :meth:`~clams.app.ClamsApp.sign_view` with the input runtime parameters for the record.
140
- #. Call :meth:`~clams.app.ClamsApp.get_configuration` to get an "upgraded" runtime parameters with default values.
141
140
  #. Call :meth:`~mmif.serialize.view.View.new_contain` on the new view object with any annotation properties specified by the configuration.
142
141
  #. Process the data and create :class:`~mmif.serialize.annotation.Annotation` objects and add them to the new view.
143
142
  #. While doing so, get help from :class:`~mmif.vocabulary.document_types.DocumentTypes`, :class:`~mmif.vocabulary.annotation_types.AnnotationTypes` classes to generate ``@type`` strings.
@@ -177,7 +176,7 @@ class ClamsApp(ABC):
177
176
  def get_configuration(self, **runtime_params):
178
177
  warnings.warn("ClamsApp.get_configuration() is deprecated. "
179
178
  "If you are using this method in `_annotate()` method,"
180
- "it is no longer needed since `clams-python==1.0.10`.",
179
+ "it is no longer needed since `clams-python>1.0.9`.",
181
180
  DeprecationWarning, stacklevel=2)
182
181
  return self._refine_params(**runtime_params)
183
182
 
@@ -195,8 +194,8 @@ class ClamsApp(ABC):
195
194
  # TODO (krim @ 8/2/23): once all devs understood this change, make runtime_conf a required argument
196
195
  if runtime_conf is None:
197
196
  warnings.warn("`runtime_conf` argument for ClamsApp.sign_view() will "
198
- "no longer be optional in the future. Please just pass "
199
- "`runtime_params` from _annotate() method.",
197
+ "no longer be optional in the future. Please pass `runtime_params` "
198
+ "from _annotate() method.",
200
199
  FutureWarning, stacklevel=2)
201
200
  view.metadata.app = self.metadata.identifier
202
201
  if runtime_conf is not None:
@@ -205,8 +204,6 @@ class ClamsApp(ABC):
205
204
  else:
206
205
  conf = runtime_conf
207
206
  view.metadata.add_parameters(**{k: str(v) for k, v in conf.items()})
208
- # TODO (krim @ 8/2/23): add "refined" parameters as well
209
- # once https://github.com/clamsproject/mmif/issues/208 is resolved
210
207
 
211
208
  def set_error_view(self, mmif: Union[str, dict, Mmif], runtime_conf: Optional[dict] = None) -> Mmif:
212
209
  """
@@ -12,7 +12,7 @@ from mmif import vocabulary
12
12
  unresolved_app_version_num = 'unresolvable'
13
13
  app_version_envvar_key = 'CLAMS_APP_VERSION'
14
14
  # type aliases to use in app metadata and runtime parameter processing
15
- primitives = Union[int, float, bool, str]
15
+ real_valued_primitives = Union[int, float, bool, str]
16
16
  # these names are taken from the JSON schema data types
17
17
  param_value_types = Literal['integer', 'number', 'string', 'boolean']
18
18
 
@@ -69,7 +69,7 @@ class Output(_BaseModel):
69
69
  alias="@type",
70
70
  description="The type of the object. Must be a IRI string."
71
71
  )
72
- properties: Dict[str, str] = pydantic.Field(
72
+ properties: Dict[str, real_valued_primitives] = pydantic.Field(
73
73
  {},
74
74
  description="(optional) Specification for type properties, if any."
75
75
  )
@@ -126,11 +126,11 @@ class RuntimeParameter(_BaseModel):
126
126
  ...,
127
127
  description=f"Type of the parameter value the app expects. Must be one of {param_value_types_values}."
128
128
  )
129
- choices: List[primitives] = pydantic.Field(
129
+ choices: List[real_valued_primitives] = pydantic.Field(
130
130
  None,
131
131
  description="(optional) List of string values that can be accepted."
132
132
  )
133
- default: primitives = pydantic.Field(
133
+ default: real_valued_primitives = pydantic.Field(
134
134
  None,
135
135
  description="(optional) Default value for the parameter. Only valid for optional parameters. Namely, setting "
136
136
  "a default value makes a parameter 'optional'."
@@ -344,9 +344,9 @@ class AppMetadata(pydantic.BaseModel):
344
344
  raise ValueError(f"Cannot add a duplicate output '{new}'.")
345
345
 
346
346
  def add_parameter(self, name: str, description: str, type: param_value_types,
347
- choices: Optional[List[primitives]] = None,
347
+ choices: Optional[List[real_valued_primitives]] = None,
348
348
  multivalued: bool = False,
349
- default: primitives = None):
349
+ default: real_valued_primitives = None):
350
350
  """
351
351
  Helper method to add an element to the ``parameters`` list.
352
352
  """
@@ -6,44 +6,27 @@ from pathlib import Path as P
6
6
  import mmif
7
7
 
8
8
 
9
- def is_valid_choice(choice):
10
- try:
11
- ichoice = int(choice)
12
- if 0 <= ichoice:
13
- return ichoice
14
- else:
15
- raise ValueError(f"\nInvalid argument for -n. Please enter a positive integer.")
16
- except ValueError:
17
- raise argparse.ArgumentTypeError(f"\nInvalid argument for -n. Please enter a positive integer.")
18
-
19
- def user_choice(mmif_obj:mmif.Mmif) -> int:
9
+ def prompt_user(mmif_obj: mmif.Mmif) -> int:
20
10
  """
21
11
  Function to ask user to choose the rewind range.
22
-
23
- :param mmif_obj: mmif object
24
- :return: int option number
25
12
  """
26
13
 
27
14
  ## Give a user options (#, "app", "timestamp") - time order
28
15
  n = len(mmif_obj.views)
29
16
  i = 0 # option number
17
+ aname = ""
18
+ a = 0
30
19
  # header
31
- print("\n" + "{:<4} {:<30} {:<100}".format("num", "timestamp", "app"))
32
- for view in mmif_obj.views:
33
- option = "{:<4} {:<30} {:<100}".format(n-i, str(view.metadata.timestamp), str(view.metadata.app))
34
- print(option)
20
+ print("\n" + "{:<8} {:<8} {:<30} {:<100}".format("view-num", "app-num", "timestamp", "app"))
21
+ for view in reversed(mmif_obj.views):
22
+ if view.metadata.app != aname:
23
+ aname = view.metadata.app
24
+ a += 1
35
25
  i += 1
26
+ print("{:<8} {:<8} {:<30} {:<100}".format(i, a, str(view.metadata.timestamp), str(view.metadata.app)))
36
27
 
37
28
  ## User input
38
- while True:
39
- choice = int(input("\nEnter the number to delete from that point by rewinding: "))
40
- try:
41
- if 0 <= choice <= n:
42
- return choice
43
- else:
44
- print(f"\nInvalid choice. Please enter an integer in the range [0, {n}].")
45
- except ValueError:
46
- print("\nInvalid input. Please enter a valid number.")
29
+ return int(input("\nEnter the number to delete from that point by rewinding: "))
47
30
 
48
31
 
49
32
  def rewind_mmif(mmif_obj: mmif.Mmif, choice: int, choice_is_viewnum: bool = True) -> mmif.Mmif:
@@ -92,24 +75,32 @@ def describe_argparser():
92
75
 
93
76
 
94
77
  def prep_argparser(**kwargs):
95
- parser = argparse.ArgumentParser(description=describe_argparser()[1], formatter_class=argparse.RawDescriptionHelpFormatter, **kwargs)
96
- parser.add_argument("mmif_file", nargs=1, help="Path to the input MMIF file, or '-' to read from stdin.")
97
- parser.add_argument("-o", '--output', default=None, metavar="PATH", help="Path to the rewound MMIF output file. When not given, the rewound MMIF is printed to stdout.")
98
- parser.add_argument("-p", '--pretty', action='store_true', help="Pretty-print rewound MMIF. True by default")
99
- parser.add_argument("-n", '--number', default="0", type=is_valid_choice, help="Number of views to rewind (default: interactive mode)")
100
- parser.add_argument("-m", '--mode', choices=['app', 'view'], default='view', help="Number of views to rewind (default: interactive mode)")
78
+ parser = argparse.ArgumentParser(description=describe_argparser()[1],
79
+ formatter_class=argparse.RawDescriptionHelpFormatter, **kwargs)
80
+ parser.add_argument("mmif_file",
81
+ help="Path to the input MMIF file, or '-' to read from stdin.")
82
+ parser.add_argument("-o", '--output', default=None, metavar="PATH",
83
+ help="Path to the rewound MMIF output file. When not given, the rewound is printed to stdout.")
84
+ parser.add_argument("-p", '--pretty', action='store_true',
85
+ help="Pretty-print rewound MMIF")
86
+ parser.add_argument("-n", '--number', default="0", type=int,
87
+ help="Number of views or apps to rewind, must be a positive integer. "
88
+ "If 0, the user will be prompted to choose. (default: 0)")
89
+ parser.add_argument("-m", '--mode', choices=['app', 'view'], default='view',
90
+ help="Choose to rewind by number of views or number of producer apps. (default: view)")
101
91
  return parser
102
92
 
103
93
 
104
94
  def main(args):
105
- mmif_obj = mmif.Mmif(sys.stdin) if args.mmif_file[0] == '-' else mmif.Mmif(open(args.mmif_file[0]).read())
95
+ mmif_obj = mmif.Mmif(str(sys.stdin)) if args.mmif_file[0] == '-' else mmif.Mmif(open(args.mmif_file).read())
106
96
 
107
- if args.number == 0: # If user doesn't know how many views to rewind, give them choices.
108
- choice = user_choice(mmif_obj)
97
+ if args.number == 0: # If user doesn't know how many views to rewind, give them choices.
98
+ choice = prompt_user(mmif_obj)
109
99
  else:
110
100
  choice = args.number
101
+ if not isinstance(choice, int) or choice <= 0:
102
+ raise ValueError(f"Only can rewind by a positive number of views. Got {choice}.")
111
103
 
112
-
113
104
  if args.output:
114
105
  # Check if the same file name exist in the path and avoid overwriting.
115
106
  output_fp = P(args.output)
@@ -132,4 +123,3 @@ if __name__ == "__main__":
132
123
  parser = prep_argparser()
133
124
  args = parser.parse_args()
134
125
  main(args)
135
-
@@ -6,7 +6,7 @@ from flask_restful import Resource, Api
6
6
  from mmif import Mmif
7
7
 
8
8
  from clams.app import ClamsApp
9
- from clams.appmetadata import primitives
9
+ from clams.appmetadata import real_valued_primitives
10
10
 
11
11
 
12
12
  class Restifier(object):
@@ -160,10 +160,10 @@ class ParameterCaster(object):
160
160
 
161
161
  :param param_spec: A specification of a data types of parameters
162
162
  """
163
- def __init__(self, param_spec: Dict[str, Tuple[primitives, bool]]):
163
+ def __init__(self, param_spec: Dict[str, Tuple[real_valued_primitives, bool]]):
164
164
  self.param_spec = param_spec
165
165
 
166
- def cast(self, args: Dict[str, List[str]]) -> Dict[str, Union[primitives, List[primitives]]]:
166
+ def cast(self, args: Dict[str, List[str]]) -> Dict[str, Union[real_valued_primitives, List[real_valued_primitives]]]:
167
167
  """
168
168
  Given parameter specification, tries to cast values of args to specified Python data types.
169
169
  Note that this caster deals with query strings, thus all keys and values in the input args are plain strings.
@@ -194,7 +194,10 @@ class ParameterCaster(object):
194
194
  else:
195
195
  casted[k] = v
196
196
  else:
197
- casted[k] = vs
197
+ if len(vs) > 1:
198
+ casted[k] = vs
199
+ else:
200
+ casted[k] = vs[0]
198
201
 
199
202
  return casted
200
203
 
@@ -0,0 +1 @@
1
+ __version__ = "1.1.2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: clams-python
3
- Version: 1.1.0
3
+ Version: 1.1.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.8
17
+ Requires-Dist: mmif-python==1.0.9
18
18
  Requires-Dist: Flask>=2
19
19
  Requires-Dist: Flask-RESTful>=0.3.9
20
20
  Requires-Dist: gunicorn>=20
@@ -33,9 +33,10 @@ Requires-Dist: jsonschema>=3
33
33
  1. a flask-based wrapper to run a Python CLAMS app as an HTTP web app
34
34
  1. cookie-cutter shell command that sets up everything and starts a new CLAMS app project
35
35
 
36
- ### Start now from [Getting Started](introduction.html)!
36
+ ### Start now from [Getting Started](https://clamsproject.github.io/clams-python/introduction.html)!
37
37
 
38
38
  ## For more ...
39
- For user manuals and Python API documentation, take a look at [Python modules](https://clams.ai/clams-python/modules.html).
40
-
41
- For MMIF-specific Python API documentation, take a look at the [mmif-python website](https://clams.ai/mmif-python).
39
+ * [Version history and patch notes](https://github.com/clamsproject/clams-python/blob/main/CHANGELOG.md)
40
+ * [CLAMS Python API documentation](https://clamsproject.github.io/clams-python/modules.html)
41
+ * [MMIF-specific Python API documentation](https://clamsproject.github.io/mmif-python)
42
+ * [Public CLAMS App Directory](https://clamsproject.github.io/apps)
@@ -1,4 +1,4 @@
1
- mmif-python==1.0.8
1
+ mmif-python==1.0.9
2
2
  Flask>=2
3
3
  Flask-RESTful>=0.3.9
4
4
  gunicorn>=20
@@ -1,4 +1,4 @@
1
- mmif-python==1.0.8
1
+ mmif-python==1.0.9
2
2
 
3
3
  Flask>=2
4
4
  Flask-RESTful>=0.3.9
@@ -127,7 +127,7 @@ class TestClamsApp(unittest.TestCase):
127
127
  self.app.metadata.add_output(AnnotationTypes.BoundingBox, boxType='text')
128
128
  metadata = json.loads(self.app.appmetadata())
129
129
  self.assertEqual(len(metadata['output']), 2)
130
- # these should not be added as a duplicate
130
+ # these should not be added because they are duplicates
131
131
  with self.assertRaises(ValueError):
132
132
  self.app.metadata.add_input(at_type=DocumentTypes.TextDocument)
133
133
  with self.assertRaises(ValueError):
@@ -240,14 +240,19 @@ class TestClamsApp(unittest.TestCase):
240
240
  with self.app.open_document_location(mmif.documents['i1'], Image.open) as f:
241
241
  self.assertEqual(f.size, (200, 71))
242
242
 
243
- def test_get_configuration(self):
243
+ def test_refine_parameters(self):
244
244
  self.app.metadata.parameters = []
245
245
  self.app.metadata.add_parameter('param1', 'first_param', 'string')
246
246
  self.app.metadata.add_parameter('param2', 'second_param', 'string', default='second_default')
247
247
  self.app.metadata.add_parameter('param3', 'third_param', 'boolean', default='f')
248
248
  self.app.metadata.add_parameter('param4', 'fourth_param', 'integer', default='1', choices="1 2 3".split())
249
249
  self.app.metadata.add_parameter('param5', 'fifth_param', 'number', default='0.5')
250
- conf = self.app.get_configuration(param1='okay', non_parameter='should be ignored')
250
+ dummy_params = {'param1': 'okay', 'non_parameter': 'should be ignored'}
251
+ conf = self.app._refine_params(**dummy_params)
252
+ # should not refine what's already refined
253
+ double_refine = self.app._refine_params(**conf)
254
+ self.assertTrue(clams.ClamsApp._RAW_PARAMS_KEY in double_refine)
255
+ self.assertEqual(double_refine, conf)
251
256
  conf.pop(clams.ClamsApp._RAW_PARAMS_KEY, None)
252
257
  self.assertEqual(len(conf), 5) # 1 from `param1`, 4 from default value
253
258
  self.assertFalse('non_parameter' in conf)
@@ -258,10 +263,10 @@ class TestClamsApp(unittest.TestCase):
258
263
  self.assertEqual(type(conf['param5']), float)
259
264
  with self.assertRaises(ValueError):
260
265
  # because param1 doesn't have a default value and thus a required param
261
- self.app.get_configuration(param2='okay')
266
+ self.app._refine_params(param2='okay')
262
267
  with self.assertRaisesRegexp(ValueError, r'.+must be one of.+'):
263
268
  # because param4 can't be 4, note that param1 is "required"
264
- self.app.get_configuration(param1='p1', param4=4)
269
+ self.app._refine_params(param1='p1', param4=4)
265
270
 
266
271
  def test_error_handling(self):
267
272
  params = {'raise_error': True, 'pretty': True}
@@ -383,7 +388,9 @@ class TestParameterCaster(unittest.TestCase):
383
388
  'number_param': ["1.11"],
384
389
  'int_param': [str(sys.maxsize)],
385
390
  'bool_param': ['true'],
386
- 'str_multi_param': ['value1', 'value2']
391
+ 'str_multi_param': ['value1', 'value2'],
392
+ 'undefined_param_single': ['undefined_value1'],
393
+ 'undefined_param_multi': ['undefined_value1', 'undefined_value2'],
387
394
  }
388
395
  self.assertTrue(all(map(lambda x: isinstance(x, str), itertools.chain.from_iterable(params.values()))))
389
396
  casted = caster.cast(params)
@@ -393,6 +400,10 @@ class TestParameterCaster(unittest.TestCase):
393
400
  self.assertTrue(isinstance(casted['int_param'], int))
394
401
  self.assertTrue(casted['bool_param'])
395
402
  self.assertEqual(set(casted['str_multi_param']), set(params['str_multi_param']))
403
+ self.assertTrue('undefined_param_single' in casted)
404
+ self.assertTrue('undefined_param_multi' in casted)
405
+ self.assertFalse(isinstance(casted['undefined_param_single'], list))
406
+ self.assertTrue(isinstance(casted['undefined_param_multi'], list))
396
407
  unknown_param_key = 'unknown'
397
408
  unknown_param_val = 'dunno'
398
409
  params[unknown_param_key] = [unknown_param_val]
@@ -1 +0,0 @@
1
- 1.1.0
@@ -1 +0,0 @@
1
- __version__ = "1.1.0"
File without changes
File without changes
File without changes
File without changes