2
2
import os
3
3
import jsonschema
4
4
import oyaml as yaml
5
+ from copy import deepcopy as dpcpy
5
6
6
7
import logmuse
7
8
from ubiquerg import VersionInHelpParser
@@ -40,6 +41,17 @@ def build_argparser():
40
41
help = "Whether to exclude the validation case from an error. "
41
42
"Only the human readable message explaining the error will be raised. "
42
43
"Useful when validating large PEPs." )
44
+
45
+ group = parser .add_mutually_exclusive_group ()
46
+
47
+ group .add_argument (
48
+ "-n" , "--sample-name" , required = False ,
49
+ help = "Name or index of the sample to validate. Only this sample will be validated." )
50
+
51
+ group .add_argument (
52
+ "-c" , "--just-config" , required = False , action = "store_true" , default = False ,
53
+ help = "Whether samples should be excluded from the validation." )
54
+
43
55
return parser
44
56
45
57
@@ -73,30 +85,97 @@ def _load_yaml(filepath):
73
85
return data
74
86
75
87
76
- def validate_project ( project , schema , exclude_case = False ):
88
+ def _read_schema ( schema ):
77
89
"""
78
- Validate a project object against a schema
90
+ Safely read schema from YAML-formatted file.
79
91
80
- :param peppy.Project project: a project object to validate
92
+ :param str | Mapping schema: path to the schema file
93
+ or schema in a dict form
94
+ :return dict: read schema
95
+ :raise TypeError: if the schema arg is neither a Mapping nor a file path
96
+ """
97
+ if isinstance (schema , str ) and os .path .isfile (schema ):
98
+ return _load_yaml (schema )
99
+ elif isinstance (schema , dict ):
100
+ return schema
101
+ raise TypeError ("schema has to be either a dict or a path to an existing file" )
102
+
103
+
104
+ def _validate_object (object , schema , exclude_case = False ):
105
+ """
106
+ Generic function to validate object against a schema
107
+
108
+ :param Mapping object: an object to validate
81
109
:param str | dict schema: schema dict to validate against or a path to one
82
110
:param bool exclude_case: whether to exclude validated objects from the error.
83
111
Useful when used ith large projects
84
112
"""
85
- if isinstance (schema , str ) and os .path .isfile (schema ):
86
- schema_dict = _load_yaml (schema )
87
- elif isinstance (schema , dict ):
88
- schema_dict = schema
89
- else :
90
- raise TypeError ("schema has to be either a dict or a path to an existing file" )
91
- project_dict = project .to_dict ()
92
113
try :
93
- jsonschema .validate (project_dict , _preprocess_schema ( schema_dict ) )
114
+ jsonschema .validate (object , schema )
94
115
except jsonschema .exceptions .ValidationError as e :
95
116
if not exclude_case :
96
117
raise e
97
118
raise jsonschema .exceptions .ValidationError (e .message )
98
119
99
120
121
+ def validate_project (project , schema , exclude_case = False ):
122
+ """
123
+ Validate a project object against a schema
124
+
125
+ :param peppy.Sample project: a project object to validate
126
+ :param str | dict schema: schema dict to validate against or a path to one
127
+ :param bool exclude_case: whether to exclude validated objects from the error.
128
+ Useful when used ith large projects
129
+ """
130
+ schema_dict = _read_schema (schema = schema )
131
+ project_dict = project .to_dict ()
132
+ _validate_object (project_dict , _preprocess_schema (schema_dict ), exclude_case )
133
+ _LOGGER .debug ("Project validation successful" )
134
+
135
+
136
+ def validate_sample (project , sample_name , schema , exclude_case = False ):
137
+ """
138
+ Validate the selected sample object against a schema
139
+
140
+ :param peppy.Project project: a project object to validate
141
+ :param str | int sample_name: name or index of the sample to validate
142
+ :param str | dict schema: schema dict to validate against or a path to one
143
+ :param bool exclude_case: whether to exclude validated objects from the error.
144
+ Useful when used ith large projects
145
+ """
146
+ schema_dict = _read_schema (schema = schema )
147
+ sample_dict = project .samples [sample_name ] if isinstance (sample_name , int ) \
148
+ else project .get_sample (sample_name )
149
+ sample_schema_dict = schema_dict ["properties" ]["samples" ]["items" ]
150
+ _validate_object (sample_dict , sample_schema_dict , exclude_case )
151
+ _LOGGER .debug ("'{}' sample validation successful" .format (sample_name ))
152
+
153
+
154
+ def validate_config (project , schema , exclude_case = False ):
155
+ """
156
+ Validate the config part of the Project object against a schema
157
+
158
+ :param peppy.Project project: a project object to validate
159
+ :param str | dict schema: schema dict to validate against or a path to one
160
+ :param bool exclude_case: whether to exclude validated objects from the error.
161
+ Useful when used ith large projects
162
+ """
163
+ schema_dict = _read_schema (schema = schema )
164
+ schema_cpy = dpcpy (schema_dict )
165
+ try :
166
+ del schema_cpy ["properties" ]["samples" ]
167
+ except KeyError :
168
+ pass
169
+ if "required" in schema_cpy :
170
+ try :
171
+ schema_cpy ["required" ].remove ("samples" )
172
+ except ValueError :
173
+ pass
174
+ project_dict = project .to_dict ()
175
+ _validate_object (project_dict , schema_cpy , exclude_case )
176
+ _LOGGER .debug ("Config validation successful" )
177
+
178
+
100
179
def main ():
101
180
""" Primary workflow """
102
181
parser = logmuse .add_logging_options (build_argparser ())
@@ -108,5 +187,18 @@ def main():
108
187
_LOGGER = logmuse .logger_via_cli (args )
109
188
_LOGGER .debug ("Creating a Project object from: {}" .format (args .pep ))
110
189
p = Project (args .pep )
111
- _LOGGER .debug ("Comparing the Project ('{}') against a schema: {}." .format (args .pep , args .schema ))
112
- validate_project (p , args .schema , args .exclude_case )
190
+ if args .sample_name :
191
+ try :
192
+ args .sample_name = int (args .sample_name )
193
+ except ValueError :
194
+ pass
195
+ _LOGGER .debug ("Comparing Sample ('{}') in the Project "
196
+ "('{}') against a schema: {}." .format (args .sample_name , args .pep , args .schema ))
197
+ validate_sample (p , args .sample_name , args .schema , args .exclude_case )
198
+ elif args .just_config :
199
+ _LOGGER .debug ("Comparing config ('{}') against a schema: {}." .format (args .pep , args .schema ))
200
+ validate_config (p , args .schema , args .exclude_case )
201
+ else :
202
+ _LOGGER .debug ("Comparing Project ('{}') against a schema: {}." .format (args .pep , args .schema ))
203
+ validate_project (p , args .schema , args .exclude_case )
204
+ _LOGGER .info ("Validation successful" )
0 commit comments