Skip to content

Commit 4120d22

Browse files
authored
Merge pull request #44 from simvue-io/validation-checks-for-RunInput
Validation checks for run input
2 parents 96bb96d + f6be06f commit 4120d22

File tree

5 files changed

+85
-10
lines changed

5 files changed

+85
-10
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
long_description_content_type="text/markdown",
1717
url="https://simvue.io",
1818
platforms=["any"],
19-
install_requires=["requests", "msgpack", "tenacity", "pyjwt", "psutil"],
19+
install_requires=["requests", "msgpack", "tenacity", "pyjwt", "psutil", "pydantic"],
2020
package_dir={'': '.'},
2121
packages=["simvue"],
2222
package_data={"": ["README.md"]},

simvue/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from simvue.run import Run
22
from simvue.client import Client
33
from simvue.handler import Handler
4+
from simvue.models import RunInput
45
__version__ = '0.7.1'

simvue/models.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from datetime import datetime
2+
3+
import re
4+
from pydantic import BaseModel, constr
5+
from typing import Optional, List, Dict, Union
6+
from enum import Enum
7+
8+
FolderStrRegex = constr(regex=r"^/.*")
9+
10+
# Pydantic class to validate run.init()
11+
class RunInput(BaseModel):
12+
name: Optional[str]
13+
metadata: Optional[Dict[str, Union[str, int, float, None]]]
14+
tags: Optional[List[str]]
15+
description: Optional[str]
16+
folder: FolderStrRegex
17+
status: Optional[str]

simvue/run.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
from .worker import Worker
1818
from .simvue import Simvue
19+
from .models import RunInput
1920
from .utilities import get_auth, get_expiry
21+
from pydantic import ValidationError
2022

2123
INIT_MISSING = 'initialize a run using init() first'
2224
QUEUE_SIZE = 10000
@@ -226,12 +228,6 @@ def init(self, name=None, metadata={}, tags=[], description=None, folder='/', ru
226228
if not re.match(r'^[a-zA-Z0-9\-\_\s\/\.:]+$', name):
227229
self._error('specified name is invalid')
228230

229-
if not isinstance(tags, list):
230-
self._error('tags must be a list')
231-
232-
if not isinstance(metadata, dict):
233-
self._error('metadata must be a dict')
234-
235231
self._name = name
236232

237233
if running:
@@ -252,16 +248,19 @@ def init(self, name=None, metadata={}, tags=[], description=None, folder='/', ru
252248
if description:
253249
data['description'] = description
254250

255-
if not folder.startswith('/'):
256-
self._error('the folder must begin with /')
257-
258251
data['folder'] = folder
259252

260253
if self._status == 'running':
261254
data['system'] = get_system()
262255

263256
self._check_token()
264257

258+
# compare with pydantic RunInput model
259+
try:
260+
runinput = RunInput(**data)
261+
except ValidationError as e:
262+
self._error(e)
263+
265264
self._simvue = Simvue(self._name, self._uuid, self._mode, self._suppress_errors)
266265
name = self._simvue.create_run(data)
267266

tests/unit/test_simvue.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,61 @@ def test_suppress_errors():
1010

1111
with pytest.raises(RuntimeError, match="suppress_errors must be boolean"):
1212
run.config(suppress_errors=200)
13+
14+
def test_run_init_metadata():
15+
"""
16+
Check that run.init throws an exception if tuples are passed into metadata dictionary
17+
"""
18+
os.environ["SIMVUE_TOKEN"] = "test"
19+
os.environ["SIMVUE_URL"] = "https://simvue.io"
20+
21+
x1_lower = 2,
22+
x1_upper = 6,
23+
24+
run = Run(mode='offline')
25+
26+
with pytest.raises(RuntimeError) as exc_info:
27+
run.init(metadata={'dataset.x1_lower': x1_lower, 'dataset.x1_upper': x1_upper},
28+
description="A test to validate inputs passed into metadata dictionary"
29+
)
30+
31+
assert exc_info.match(r"value is not a valid integer")
32+
33+
def test_run_init_tags():
34+
"""
35+
Check that run.init throws an exception if tags are not a list
36+
"""
37+
os.environ["SIMVUE_TOKEN"] = "test"
38+
os.environ["SIMVUE_URL"] = "https://simvue.io"
39+
40+
x1_lower = 2
41+
x1_upper = 6
42+
43+
run = Run(mode='offline')
44+
45+
with pytest.raises(RuntimeError) as exc_info:
46+
run.init(metadata={'dataset.x1_lower': x1_lower, 'dataset.x1_upper': x1_upper}, tags=1,
47+
description="A test to validate tag inputs passed into run.init"
48+
)
49+
50+
assert exc_info.match(r"value is not a valid list")
51+
52+
def test_run_init_folder():
53+
"""
54+
Check that run.init throws an exception if folder input is not specified correctly
55+
"""
56+
os.environ["SIMVUE_TOKEN"] = "test"
57+
os.environ["SIMVUE_URL"] = "https://simvue.io"
58+
59+
x1_lower = 2
60+
x1_upper = 6
61+
62+
run = Run(mode='offline')
63+
64+
with pytest.raises(RuntimeError) as exc_info:
65+
run.init(metadata={'dataset.x1_lower': x1_lower, 'dataset.x1_upper': x1_upper}, tags=[1,2,3], folder='test_folder',
66+
description="A test to validate folder input passed into run.init"
67+
)
68+
69+
assert exc_info.match(r"string does not match regex")
70+

0 commit comments

Comments
 (0)