• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RDFLib / pySHACL / 126

pending completion
126

push

PySHACL-Drone

Ashley Sommer
Ruff formatting fixes

5 of 5 new or added lines in 5 files covered. (100.0%)

5672 of 7350 relevant lines covered (77.17%)

0.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pyshacl/cli.py
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3

4
import argparse
×
5
import os
×
6
import sys
×
7

8
from prettytable import PrettyTable
×
9
from rdflib.namespace import SH
×
10

11
from pyshacl import __version__, validate
×
12
from pyshacl.errors import (
×
13
    ConstraintLoadError,
14
    ReportableRuntimeError,
15
    RuleLoadError,
16
    ShapeLoadError,
17
    ValidationFailure,
18
)
19

20

21
class ShowVersion(argparse.Action):
×
22
    def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, help=None):
×
23
        super(ShowVersion, self).__init__(
×
24
            option_strings=option_strings, dest=dest, default=default, nargs=0, help=help
25
        )
26

27
    def __call__(self, parser, namespace, values, option_string=None):
×
28
        # parser.exit() writes message to stderr before calling sys.exit()
29
        parser.exit(status=0, message="PySHACL Version: " + str(__version__) + "\n")
×
30

31

32
def str_is_true(s_var: str):
×
33
    if len(s_var) > 0:
×
34
        if s_var.lower() not in ("0", "f", "n", "false", "no"):
×
35
            return True
×
36
    return False
×
37

38

39
parser = argparse.ArgumentParser(description='PySHACL {} Validator command line tool.'.format(str(__version__)))
×
40
parser.add_argument(
×
41
    'data',
42
    metavar='DataGraph',
43
    type=argparse.FileType('rb'),
44
    help='The file containing the Target Data Graph.',
45
    default=None,
46
    nargs='?',
47
)
48
parser.add_argument(
×
49
    '-s', '--shacl', dest='shacl', action='store', nargs='?', help='A file containing the SHACL Shapes Graph.'
50
)
51
parser.add_argument(
×
52
    '-e',
53
    '--ont-graph',
54
    dest='ont',
55
    action='store',
56
    nargs='?',
57
    help='A file path or URL to a document containing extra ontological information. '
58
    'RDFS and OWL definitions from this are used to inoculate the DataGraph.',
59
)
60
parser.add_argument(
×
61
    '-i',
62
    '--inference',
63
    dest='inference',
64
    action='store',
65
    default='none',
66
    choices=('none', 'rdfs', 'owlrl', 'both'),
67
    help='Choose a type of inferencing to run against the Data Graph before validating.',
68
)
69
parser.add_argument(
×
70
    '-m',
71
    '--metashacl',
72
    dest='metashacl',
73
    action='store_true',
74
    default=False,
75
    help='Validate the SHACL Shapes graph against the shacl-shacl Shapes Graph before validating the Data Graph.',
76
)
77
parser.add_argument(
×
78
    '-im',
79
    '--imports',
80
    dest='imports',
81
    action='store_true',
82
    default=False,
83
    help='Allow import of sub-graphs defined in statements with owl:imports.',
84
)
85
parser.add_argument(
×
86
    '-a',
87
    '--advanced',
88
    dest='advanced',
89
    action='store_true',
90
    default=False,
91
    help='Enable features from the SHACL Advanced Features specification.',
92
)
93
parser.add_argument(
×
94
    '-j',
95
    '--js',
96
    dest='js',
97
    action='store_true',
98
    default=False,
99
    help='Enable features from the SHACL-JS Specification.',
100
)
101
parser.add_argument(
×
102
    '-it',
103
    '--iterate-rules',
104
    dest='iterate_rules',
105
    action='store_true',
106
    default=False,
107
    help="Run Shape's SHACL Rules iteratively until the data_graph reaches a steady state.",
108
)
109
parser.add_argument('--abort', dest='abort', action='store_true', default=False, help='Abort on first invalid data.')
×
110
parser.add_argument(
×
111
    '--allow-info',
112
    '--allow-infos',
113
    dest='allow_infos',
114
    action='store_true',
115
    default=False,
116
    help='Shapes marked with severity of Info will not cause result to be invalid.',
117
)
118
parser.add_argument(
×
119
    '-w',
120
    '--allow-warning',
121
    '--allow-warnings',
122
    dest='allow_warnings',
123
    action='store_true',
124
    default=False,
125
    help='Shapes marked with severity of Warning or Info will not cause result to be invalid.',
126
)
127
parser.add_argument(
×
128
    '-d', '--debug', dest='debug', action='store_true', default=False, help='Output additional runtime messages.'
129
)
130
parser.add_argument(
×
131
    '-f',
132
    '--format',
133
    dest='format',
134
    action='store',
135
    help='Choose an output format. Default is \"human\".',
136
    default='human',
137
    choices=('human', 'table', 'turtle', 'xml', 'json-ld', 'nt', 'n3'),
138
)
139
parser.add_argument(
×
140
    '-df',
141
    '--data-file-format',
142
    dest='data_file_format',
143
    action='store',
144
    help='Explicitly state the RDF File format of the input DataGraph file. Default=\"auto\".',
145
    default='auto',
146
    choices=('auto', 'turtle', 'xml', 'json-ld', 'nt', 'n3'),
147
)
148
parser.add_argument(
×
149
    '-sf',
150
    '--shacl-file-format',
151
    dest='shacl_file_format',
152
    action='store',
153
    help='Explicitly state the RDF File format of the input SHACL file. Default=\"auto\".',
154
    default='auto',
155
    choices=('auto', 'turtle', 'xml', 'json-ld', 'nt', 'n3'),
156
)
157
parser.add_argument(
×
158
    '-ef',
159
    '--ont-file-format',
160
    dest='ont_file_format',
161
    action='store',
162
    help='Explicitly state the RDF File format of the extra ontology file. Default=\"auto\".',
163
    default='auto',
164
    choices=('auto', 'turtle', 'xml', 'json-ld', 'nt', 'n3'),
165
)
166
parser.add_argument('-V', '--version', action=ShowVersion, help='Show PySHACL version and exit.')
×
167
parser.add_argument(
×
168
    '-o',
169
    '--output',
170
    dest='output',
171
    nargs='?',
172
    type=argparse.FileType('w'),
173
    help='Send output to a file (defaults to stdout).',
174
    default=sys.stdout,
175
)
176
parser.add_argument(
×
177
    '--server',
178
    help='Ignore all the rest of the options, start the HTTP Server. Same as `pyshacl_server`.',
179
    action='store_true',
180
    dest='server',
181
    default=False,
182
)
183
# parser.add_argument('-h', '--help', action="help", help='Show this help text.')
184

185

186
def main():
×
187
    basename = os.path.basename(sys.argv[0])
×
188
    if basename == "__main__.py":
×
189
        parser.prog = "python3 -m pyshacl"
×
190
    do_server = os.getenv("PYSHACL_HTTP", "")
×
191
    do_server = os.getenv("PYSHACL_SERVER", do_server)
×
192
    if do_server:
×
193
        args = {}
×
194
    else:
195
        args = parser.parse_args()
×
196
    if str_is_true(do_server) or args.server:
×
197
        from pyshacl.sh_http import cli as http_cli
×
198

199
        sys.exit(http_cli())
×
200
    elif not args.data:
×
201
        # No datafile give, and not starting in server mode.
202
        sys.stderr.write('Validation Error. No DataGraph file supplied.\n')
×
203
        parser.print_usage(sys.stderr)
×
204
        sys.exit(1)
×
205
    validator_kwargs = {'debug': args.debug}
×
206
    if args.shacl is not None:
×
207
        validator_kwargs['shacl_graph'] = args.shacl
×
208
    if args.ont is not None:
×
209
        validator_kwargs['ont_graph'] = args.ont
×
210
    if args.format not in ['human', 'table']:
×
211
        validator_kwargs['serialize_report_graph'] = args.format
×
212
    if args.inference != 'none':
×
213
        validator_kwargs['inference'] = args.inference
×
214
    if args.imports:
×
215
        validator_kwargs['do_owl_imports'] = True
×
216
    if args.metashacl:
×
217
        validator_kwargs['meta_shacl'] = True
×
218
    if args.advanced:
×
219
        validator_kwargs['advanced'] = True
×
220
    if args.js:
×
221
        validator_kwargs['js'] = True
×
222
    if args.iterate_rules:
×
223
        if not args.advanced:
×
224
            sys.stderr.write("Iterate-Rules option only works when you enable Advanced Mode.\n")
×
225
        else:
226
            validator_kwargs['iterate_rules'] = True
×
227
    if args.abort:
×
228
        validator_kwargs['abort_on_first'] = True
×
229
    if args.allow_infos:
×
230
        validator_kwargs['allow_infos'] = True
×
231
    if args.allow_warnings:
×
232
        validator_kwargs['allow_warnings'] = True
×
233
    if args.shacl_file_format:
×
234
        _f: str = args.shacl_file_format
×
235
        if _f != "auto":
×
236
            validator_kwargs['shacl_graph_format'] = _f
×
237
    if args.ont_file_format:
×
238
        _f = args.ont_file_format
×
239
        if _f != "auto":
×
240
            validator_kwargs['ont_graph_format'] = _f
×
241
    if args.data_file_format:
×
242
        _f = args.data_file_format
×
243
        if _f != "auto":
×
244
            validator_kwargs['data_graph_format'] = _f
×
245
    try:
×
246
        is_conform, v_graph, v_text = validate(args.data, **validator_kwargs)
×
247
        if isinstance(v_graph, BaseException):
×
248
            raise v_graph
×
249
    except ValidationFailure as vf:
×
250
        args.output.write("Validator generated a Validation Failure result:\n")
×
251
        args.output.write(str(vf.message))
×
252
        args.output.write("\n")
×
253
        sys.exit(1)
×
254
    except ShapeLoadError as sle:
×
255
        sys.stderr.write("Validator encountered a Shape Load Error:\n")
×
256
        sys.stderr.write(str(sle))
×
257
        sys.exit(2)
×
258
    except ConstraintLoadError as cle:
×
259
        sys.stderr.write("Validator encountered a Constraint Load Error:\n")
×
260
        sys.stderr.write(str(cle))
×
261
        sys.exit(2)
×
262
    except RuleLoadError as rle:
×
263
        sys.stderr.write("Validator encountered a Rule Load Error:\n")
×
264
        sys.stderr.write(str(rle))
×
265
        sys.exit(2)
×
266
    except ReportableRuntimeError as rre:
×
267
        sys.stderr.write("Validator encountered a Runtime Error:\n")
×
268
        sys.stderr.write(str(rre.message))
×
269
        sys.stderr.write("\nIf you believe this is a bug in pyshacl, open an Issue on the pyshacl github page.\n")
×
270
        sys.exit(2)
×
271
    except NotImplementedError as nie:
×
272
        sys.stderr.write("Validator feature is not implemented:\n")
×
273
        sys.stderr.write(str(nie.args[0]))
×
274
        sys.stderr.write("\nIf your use-case requires this feature, open an Issue on the pyshacl github page.\n")
×
275
        sys.exit(3)
×
276
    except RuntimeError as re:
×
277
        import traceback
×
278

279
        traceback.print_tb(re.__traceback__)
×
280
        sys.stderr.write(
×
281
            "\n\nValidator encountered a Runtime Error. Please report this to the PySHACL issue tracker.\n"
282
        )
283
        sys.exit(2)
×
284

285
    if args.format == 'human':
×
286
        args.output.write(v_text)
×
287
    elif args.format == 'table':
×
288
        t1 = PrettyTable()
×
289
        t1.field_names = ["Conforms"]
×
290
        t1.align = "c"
×
291
        t1.add_row([is_conform])
×
292
        args.output.write(str(t1))
×
293
        args.output.write('\n\n')
×
294

295
        def col_widther(s, w):
×
296
            """Split strings to a given width for table"""
297
            s2 = []
×
298
            i = 0
×
299
            while i < len(s):
×
300
                s2.append(s[i : i + w])
×
301
                i += w
×
302
            return '\n'.join(s2)
×
303

304
        if not is_conform:
×
305
            t2 = PrettyTable()
×
306
            t2.field_names = ['No.', 'Severity', 'Focus Node', 'Result Path', 'Message', 'Component', 'Shape', 'Value']
×
307
            t2.align = "l"
×
308

309
            for i, o in enumerate(v_graph.objects(None, SH.result)):
×
310
                r = {}
×
311
                for o2 in v_graph.predicate_objects(o):
×
312
                    r[o2[0]] = str(col_widther(o2[1].replace(f'{SH}', ''), 25))  # max col width 30 chars
×
313
                t2.add_row(
×
314
                    [
315
                        i + 1,
316
                        r[SH.resultSeverity],
317
                        r[SH.focusNode],
318
                        r[SH.resultPath] if r.get(SH.resultPath) is not None else '-',
319
                        r[SH.resultMessage] if r.get(SH.resultMessage) is not None else '-',
320
                        r[SH.sourceConstraintComponent],
321
                        r[SH.sourceShape],
322
                        r[SH.value] if r.get(SH.value) is not None else '-',
323
                    ]
324
                )
325
                t2.add_row(['', '', '', '', '', '', '', ''])
×
326
            args.output.write(str(t2))
×
327
    else:
328
        if isinstance(v_graph, bytes):
×
329
            v_graph = v_graph.decode('utf-8')
×
330
        args.output.write(v_graph)
×
331
    args.output.close()
×
332
    if is_conform:
×
333
        sys.exit(0)
×
334
    else:
335
        sys.exit(1)
×
336

337

338
if __name__ == "__main__":
×
339
    main()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc