bupa1018 commited on
Commit
78c3736
·
1 Parent(s): 01f944d

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. data/test/collections.py +526 -0
data/test/collections.py ADDED
@@ -0,0 +1,526 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 Karlsruhe Institute of Technology
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ import sys
15
+ from functools import wraps
16
+
17
+ import click
18
+ from niquests.exceptions import ConnectionError
19
+ from niquests.exceptions import MissingSchema
20
+ from niquests.exceptions import SSLError
21
+ from xmlhelpy import Choice
22
+ from xmlhelpy import Integer
23
+ from xmlhelpy import IntRange
24
+ from xmlhelpy import TokenList
25
+ from xmlhelpy import option
26
+
27
+ from kadi_apy.cli.core import CLIKadiManager
28
+ from kadi_apy.globals import Verbose
29
+ from kadi_apy.lib.core import KadiManager
30
+ from kadi_apy.lib.exceptions import KadiAPYConfigurationError
31
+ from kadi_apy.lib.exceptions import KadiAPYException
32
+ from kadi_apy.lib.exceptions import KadiAPYInputError
33
+ from kadi_apy.lib.utils import get_resource_type
34
+
35
+
36
+ _identity_types = ["ldap", "local", "shib"]
37
+
38
+
39
+ def apy_command(use_kadi_manager=False):
40
+ r"""Decorator to handle the default arguments and exceptions of an APY command.
41
+
42
+ This function inits the :class:`.KadiManager` or :class:`.CLIKadiManager` and
43
+ includes it as ``manager`` to ``**kwargs``. It adds the options ``instance`` and
44
+ ``verbose`` to the CLI tool.
45
+
46
+ :param use_kadi_manager: Flag to use the :class:`.KadiManager` instead of the
47
+ :class:`.CLIKadiManager`.
48
+ :type use_kadi_manager: bool, optional
49
+ """
50
+
51
+ def decorator(func):
52
+ option(
53
+ "instance",
54
+ char="I",
55
+ description="Name of a Kadi instance defined in the config file.",
56
+ )(func)
57
+
58
+ option(
59
+ "verbose",
60
+ char="V",
61
+ description="Verbose level to define the amount of print output.",
62
+ default="info",
63
+ param_type=Choice(["error", "warning", "info", "debug"]),
64
+ )(func)
65
+
66
+ @wraps(func)
67
+ def decorated_command(instance, verbose, *args, **kwargs):
68
+ try:
69
+ if use_kadi_manager:
70
+ kwargs["manager"] = KadiManager(
71
+ instance=instance, verbose=Verbose[verbose.upper()]
72
+ )
73
+ else:
74
+ kwargs["manager"] = CLIKadiManager(
75
+ instance=instance, verbose=Verbose[verbose.upper()]
76
+ )
77
+ except KadiAPYConfigurationError as e:
78
+ click.echo(e, err=True)
79
+ sys.exit(1)
80
+
81
+ try:
82
+ func(*args, **kwargs)
83
+ except KadiAPYException as e:
84
+ click.echo(e, err=True)
85
+ sys.exit(1)
86
+ except SSLError as e:
87
+ click.echo(e, err=True)
88
+ click.echo(
89
+ "Use 'verify = False' in the config file to skip verifying the"
90
+ " SSL/TLS certificate of the host (not recommended) or include a"
91
+ " path to certificates of trusted CAs in the config file via"
92
+ " 'ca_bundle = /path/to/certfile'."
93
+ )
94
+ sys.exit(1)
95
+ except MissingSchema as e:
96
+ click.echo(e, err=True)
97
+ click.echo(
98
+ "Please check the host information since the URL schema (e.g. http"
99
+ " or https) is missing."
100
+ )
101
+ sys.exit(1)
102
+ except ConnectionError as e:
103
+ click.echo(e, err=True)
104
+ host = kwargs["manager"].host
105
+ click.echo(
106
+ f"Could not connect to the host ({host}). It could be that the host"
107
+ " is temporarily unavailable or the URL is incorrect."
108
+ )
109
+ sys.exit(1)
110
+
111
+ return decorated_command
112
+
113
+ # Decoration without parentheses.
114
+ if callable(use_kadi_manager):
115
+ return apy_command()(use_kadi_manager)
116
+
117
+ return decorator
118
+
119
+
120
+ def id_identifier_options(
121
+ class_type,
122
+ keep_manager=False,
123
+ helptext=None,
124
+ name=None,
125
+ required=True,
126
+ char=None,
127
+ allow_tokenlist=False,
128
+ tokenlist_name=None,
129
+ tokenlist_char="T",
130
+ ):
131
+ r"""Decorator to handle the common ID and identifier options of commands.
132
+
133
+ This function inits a resource and includes it to ``**kwargs``. It adds the options
134
+ to read the ID or the identifier of the resource to the CLI tool.
135
+
136
+ :param class_type: The resource type defined either as string or class.
137
+ :param keep_manager: Whether to keep the manager for further use.
138
+ :type keep_manager: bool, optional
139
+ :param helptext: Text to describe the input.
140
+ :type helptext: str, optional
141
+ :param name: Name to better describe the input.
142
+ :type name: str, optional
143
+ :param required: Whether the parameter is required.
144
+ :type required: bool, optional
145
+ :param char: Char for the options.
146
+ :type char: str, optional
147
+ :param allow_tokenlist: Flag indicating if a tokenlist should be an option for
148
+ input. If ``True`` the manager is passed to the function even if
149
+ ``keep_manager`` is ``False``.
150
+ :type allow_tokenlist: bool, optional
151
+ :param tokenlist_name: Name of the tokenlist.
152
+ :type tokenlist_name: str, optional
153
+ :param tokenlist_char: Char for the tokenlist.
154
+ :type tokenlist_char: str, optional
155
+ """
156
+
157
+ def decorator(func):
158
+ if isinstance(class_type, str):
159
+ resource = get_resource_type(class_type)
160
+ else:
161
+ resource = class_type
162
+
163
+ help_id = f"ID of the {resource.name}"
164
+ if helptext:
165
+ help_id = f"{help_id} {helptext}"
166
+ else:
167
+ help_id = help_id + "."
168
+
169
+ help_identifier = f"Identifier of the {resource.name}"
170
+ if helptext:
171
+ help_identifier = f"{help_identifier} {helptext}"
172
+ else:
173
+ help_identifier = help_identifier + "."
174
+
175
+ char_option_1 = None
176
+ char_option_2 = None
177
+
178
+ if name is None:
179
+ text_option = f"{resource.name}-id"
180
+ if not char:
181
+ char_option_1 = f"{resource.name[0].lower()}"
182
+ else:
183
+ text_option = f"{resource.name}-id-{name.lower()}"
184
+ if not char:
185
+ char_option_1 = f"{name[0].lower()}"
186
+
187
+ if char:
188
+ char_option_1 = f"{char[0].lower()}"
189
+ char_option_2 = f"{char[0].upper()}"
190
+
191
+ option(
192
+ text_option,
193
+ char=char_option_1,
194
+ description=help_id,
195
+ param_type=Integer,
196
+ default=None,
197
+ )(func)
198
+
199
+ if allow_tokenlist:
200
+ tokenlist_description = f"Tokenlist of {resource.name} IDs"
201
+ if helptext:
202
+ tokenlist_description = f"{tokenlist_description} {helptext}"
203
+ else:
204
+ tokenlist_description = help_id + "."
205
+
206
+ if tokenlist_name is None:
207
+ text_tokenlist_option = f"{resource.name}-ids"
208
+ else:
209
+ text_tokenlist_option = tokenlist_name
210
+
211
+ option(
212
+ text_tokenlist_option,
213
+ char=tokenlist_char,
214
+ description=tokenlist_description,
215
+ param_type=TokenList,
216
+ )(func)
217
+
218
+ if name is None:
219
+ text_option = f"{resource.name}-identifier"
220
+ if not char:
221
+ char_option_2 = f"{resource.name[0].upper()}"
222
+ else:
223
+ text_option = f"{resource.name}-identifier-{name.lower()}"
224
+ if not char:
225
+ char_option_2 = f"{name[0].upper()}"
226
+
227
+ option(
228
+ text_option,
229
+ char=char_option_2,
230
+ description=help_identifier,
231
+ default=None,
232
+ )(func)
233
+
234
+ @wraps(func)
235
+ def decorated_command(manager, *args, **kwargs):
236
+ if name is None:
237
+ text_id = f"{resource.name}_id"
238
+ text_identifier = f"{resource.name}_identifier"
239
+ else:
240
+ text_id = f"{resource.name}_id_{name.lower()}"
241
+ text_identifier = f"{resource.name}_identifier_{name.lower()}"
242
+
243
+ item_id = kwargs[str(text_id)]
244
+ item_identifier = kwargs[f"{text_identifier}"]
245
+
246
+ if (item_id is None and item_identifier is None and required) or (
247
+ item_id is not None and item_identifier is not None
248
+ ):
249
+ exit = False
250
+ if allow_tokenlist:
251
+ if tokenlist_name is None:
252
+ text_tokenlist_option = f"{resource.name}_ids"
253
+ else:
254
+ text_tokenlist_option = tokenlist_name
255
+
256
+ if kwargs[str(text_tokenlist_option)] is None:
257
+ text = (
258
+ f"Please specify the {resource.name} ids via"
259
+ f" '{text_tokenlist_option}' or either the id or the"
260
+ f" identifier of the {resource.name}"
261
+ )
262
+ exit = True
263
+ else:
264
+ text = (
265
+ f"Please specify either the id or the identifier of the"
266
+ f" {resource.name}"
267
+ )
268
+ exit = True
269
+
270
+ if exit:
271
+ if helptext:
272
+ text = f"{text} {helptext}"
273
+ else:
274
+ text = f"{text}."
275
+ click.echo(text)
276
+ sys.exit(1)
277
+
278
+ # Init the item either by the id or the identifier.
279
+ # The item is directly passed to the function as e.g. record in case of
280
+ # records or {name} if a name is given. If no information is given, None is
281
+ # returned.
282
+ if item_id is not None or item_identifier is not None:
283
+ item = getattr(manager, resource.name)(
284
+ identifier=item_identifier, id=item_id
285
+ )
286
+ else:
287
+ item = None
288
+
289
+ if name is None:
290
+ kwargs[str(resource.name)] = item
291
+ else:
292
+ kwargs[f"{name.lower()}"] = item
293
+
294
+ del kwargs[str(text_id)]
295
+ del kwargs[str(text_identifier)]
296
+
297
+ if keep_manager or allow_tokenlist:
298
+ kwargs["manager"] = manager
299
+
300
+ func(*args, **kwargs)
301
+
302
+ return decorated_command
303
+
304
+ return decorator
305
+
306
+
307
+ def user_id_options(helptext=None, required=True, keep_manager=False):
308
+ r"""Decorator to handle options to identify a user.
309
+
310
+ This function inits a :class:`.CLIUser` and includes it to ``**kwargs``. Is adds
311
+ the options to read the user ID, username and identity-type to the CLI tool.
312
+
313
+ :param helptext: Text to describe the input.
314
+ :type helptext: str, optional
315
+ :param keep_manager: Whether to keep the manager for further use.
316
+ :type keep_manager: bool, optional
317
+ :param required: Whether to init the user is required.
318
+ :type required: bool, optional
319
+ """
320
+
321
+ def decorator(func):
322
+ description = "ID of the user"
323
+ if helptext:
324
+ description = f"{description} {helptext}"
325
+ else:
326
+ description = description + "."
327
+
328
+ option(
329
+ "user",
330
+ char="u",
331
+ description=description,
332
+ default=None,
333
+ param_type=Integer,
334
+ )(func)
335
+
336
+ description = "Username of the user"
337
+ if helptext:
338
+ description = f"{description} {helptext}"
339
+ else:
340
+ description = description + "."
341
+
342
+ option(
343
+ "username",
344
+ char="U",
345
+ description=description,
346
+ default=None,
347
+ )(func)
348
+
349
+ description = "Identity type of the user"
350
+ if helptext:
351
+ description = f"{description} {helptext}"
352
+
353
+ option(
354
+ "identity-type",
355
+ char="D",
356
+ description=description,
357
+ param_type=Choice(_identity_types),
358
+ )(func)
359
+
360
+ @wraps(func)
361
+ def decorated_command(user, username, identity_type, manager, *args, **kwargs):
362
+ if user is None and username is None:
363
+ if required:
364
+ raise KadiAPYInputError(
365
+ "Please specify the user via id or username and identity type."
366
+ )
367
+ kwargs["user"] = None
368
+
369
+ elif username is not None and identity_type is None:
370
+ raise KadiAPYInputError(
371
+ f"Please specify the identity type to username '{username}'."
372
+ f" The following types are available {_identity_types}."
373
+ )
374
+ else:
375
+ kwargs["user"] = manager.user(
376
+ id=user, username=username, identity_type=identity_type
377
+ )
378
+
379
+ if keep_manager:
380
+ kwargs["manager"] = manager
381
+
382
+ func(*args, **kwargs)
383
+
384
+ return decorated_command
385
+
386
+ return decorator
387
+
388
+
389
+ def file_id_options(helptext=None, required=True, name=None, char=None):
390
+ r"""Decorator to handle options to identify a file of a record.
391
+
392
+ :param helptext: Text to describe the input.
393
+ :type helptext: str, optional
394
+ :param required: Whether to init the file is required.
395
+ :type required: bool, optional
396
+ :param name: Name to better describe the input.
397
+ :type name: str, optional
398
+ :param char: Char for the options.
399
+ :type char: str, optional
400
+ """
401
+
402
+ def decorator(func):
403
+ description = "Name of the file"
404
+ if helptext:
405
+ description = f"{description} {helptext}"
406
+ else:
407
+ description = description + "."
408
+
409
+ char_option_1 = None
410
+ char_option_2 = None
411
+
412
+ if name is None:
413
+ text_option = "file-name"
414
+ if not char:
415
+ char_option_1 = "n"
416
+ else:
417
+ text_option = f"{name}-name"
418
+ if not char:
419
+ char_option_1 = f"{name[0].lower()}"
420
+
421
+ if char:
422
+ char_option_1 = f"{char[0].lower()}"
423
+ char_option_2 = f"{char[0].upper()}"
424
+
425
+ option(
426
+ text_option,
427
+ char=char_option_1,
428
+ description=description,
429
+ default=None,
430
+ )(func)
431
+
432
+ description = "ID of the file"
433
+ if helptext:
434
+ description = f"{description} {helptext}"
435
+ else:
436
+ description = description + "."
437
+
438
+ if name is None:
439
+ text_option = "file-id"
440
+ if not char:
441
+ char_option_2 = "i"
442
+ else:
443
+ text_option = f"{name}-id"
444
+ if not char:
445
+ char_option_2 = f"{name[0].upper()}"
446
+
447
+ option(
448
+ text_option,
449
+ char=char_option_2,
450
+ description=description,
451
+ default=None,
452
+ )(func)
453
+
454
+ @wraps(func)
455
+ def decorated_command(*args, **kwargs):
456
+ if name is None:
457
+ text_id = "file_id"
458
+ text_name = "file_name"
459
+ else:
460
+ text_id = f"{name}_id"
461
+ text_name = f"{name}_name"
462
+
463
+ file_id = kwargs[str(text_id)]
464
+ file_name = kwargs[str(text_name)]
465
+
466
+ if required:
467
+ if (file_name is None and file_id is None) or (
468
+ file_name is not None and file_id is not None
469
+ ):
470
+ text = "Please specify either the name or the id of the file"
471
+ if helptext:
472
+ text = f"{text} {helptext}"
473
+ click.echo(f"{text}.")
474
+ sys.exit(1)
475
+
476
+ if file_name:
477
+ record = kwargs["record"]
478
+ kwargs[str(text_id)] = record.get_file_id(file_name)
479
+ else:
480
+ kwargs[str(text_id)] = file_id
481
+
482
+ del kwargs[str(text_name)]
483
+
484
+ func(*args, **kwargs)
485
+
486
+ return decorated_command
487
+
488
+ return decorator
489
+
490
+
491
+ def search_pagination_options(description_page=None):
492
+ r"""Decorator to add two parameters for the search.
493
+
494
+ :param description_page: Description of the ``page`` option.
495
+ :type description_page: str, optional
496
+ """
497
+
498
+ def decorator(func):
499
+ description = "Page for search results."
500
+ if description_page is not None:
501
+ description = description_page
502
+ option(
503
+ "page",
504
+ char="p",
505
+ description=description,
506
+ param_type=IntRange(min=1),
507
+ default=1,
508
+ )(func)
509
+ option(
510
+ "per-page",
511
+ char="n",
512
+ description="Number of results per page.",
513
+ param_type=IntRange(1, 100),
514
+ default=10,
515
+ )(func)
516
+
517
+ @wraps(func)
518
+ def decorated_command(*args, **kwargs):
519
+ func(*args, **kwargs)
520
+
521
+ return decorated_command
522
+
523
+ if callable(description_page):
524
+ return search_pagination_options()(description_page)
525
+
526
+ return decorator