outerbounds 0.3.55rc3__py3-none-any.whl → 0.3.133__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. outerbounds/_vendor/PyYAML.LICENSE +20 -0
  2. outerbounds/_vendor/__init__.py +0 -0
  3. outerbounds/_vendor/_yaml/__init__.py +34 -0
  4. outerbounds/_vendor/click/__init__.py +73 -0
  5. outerbounds/_vendor/click/_compat.py +626 -0
  6. outerbounds/_vendor/click/_termui_impl.py +717 -0
  7. outerbounds/_vendor/click/_textwrap.py +49 -0
  8. outerbounds/_vendor/click/_winconsole.py +279 -0
  9. outerbounds/_vendor/click/core.py +2998 -0
  10. outerbounds/_vendor/click/decorators.py +497 -0
  11. outerbounds/_vendor/click/exceptions.py +287 -0
  12. outerbounds/_vendor/click/formatting.py +301 -0
  13. outerbounds/_vendor/click/globals.py +68 -0
  14. outerbounds/_vendor/click/parser.py +529 -0
  15. outerbounds/_vendor/click/py.typed +0 -0
  16. outerbounds/_vendor/click/shell_completion.py +580 -0
  17. outerbounds/_vendor/click/termui.py +787 -0
  18. outerbounds/_vendor/click/testing.py +479 -0
  19. outerbounds/_vendor/click/types.py +1073 -0
  20. outerbounds/_vendor/click/utils.py +580 -0
  21. outerbounds/_vendor/click.LICENSE +28 -0
  22. outerbounds/_vendor/vendor_any.txt +2 -0
  23. outerbounds/_vendor/yaml/__init__.py +471 -0
  24. outerbounds/_vendor/yaml/_yaml.cpython-311-darwin.so +0 -0
  25. outerbounds/_vendor/yaml/composer.py +146 -0
  26. outerbounds/_vendor/yaml/constructor.py +862 -0
  27. outerbounds/_vendor/yaml/cyaml.py +177 -0
  28. outerbounds/_vendor/yaml/dumper.py +138 -0
  29. outerbounds/_vendor/yaml/emitter.py +1239 -0
  30. outerbounds/_vendor/yaml/error.py +94 -0
  31. outerbounds/_vendor/yaml/events.py +104 -0
  32. outerbounds/_vendor/yaml/loader.py +62 -0
  33. outerbounds/_vendor/yaml/nodes.py +51 -0
  34. outerbounds/_vendor/yaml/parser.py +629 -0
  35. outerbounds/_vendor/yaml/reader.py +208 -0
  36. outerbounds/_vendor/yaml/representer.py +378 -0
  37. outerbounds/_vendor/yaml/resolver.py +245 -0
  38. outerbounds/_vendor/yaml/scanner.py +1555 -0
  39. outerbounds/_vendor/yaml/serializer.py +127 -0
  40. outerbounds/_vendor/yaml/tokens.py +129 -0
  41. outerbounds/command_groups/apps_cli.py +450 -0
  42. outerbounds/command_groups/cli.py +9 -5
  43. outerbounds/command_groups/local_setup_cli.py +249 -33
  44. outerbounds/command_groups/perimeters_cli.py +231 -33
  45. outerbounds/command_groups/tutorials_cli.py +111 -0
  46. outerbounds/command_groups/workstations_cli.py +88 -15
  47. outerbounds/utils/kubeconfig.py +2 -2
  48. outerbounds/utils/metaflowconfig.py +111 -21
  49. outerbounds/utils/schema.py +8 -2
  50. outerbounds/utils/utils.py +19 -0
  51. outerbounds/vendor.py +159 -0
  52. {outerbounds-0.3.55rc3.dist-info → outerbounds-0.3.133.dist-info}/METADATA +17 -6
  53. outerbounds-0.3.133.dist-info/RECORD +59 -0
  54. {outerbounds-0.3.55rc3.dist-info → outerbounds-0.3.133.dist-info}/WHEEL +1 -1
  55. outerbounds-0.3.55rc3.dist-info/RECORD +0 -15
  56. {outerbounds-0.3.55rc3.dist-info → outerbounds-0.3.133.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,580 @@
1
+ import os
2
+ import re
3
+ import sys
4
+ import typing as t
5
+ from functools import update_wrapper
6
+ from types import ModuleType
7
+
8
+ from ._compat import _default_text_stderr
9
+ from ._compat import _default_text_stdout
10
+ from ._compat import _find_binary_writer
11
+ from ._compat import auto_wrap_for_ansi
12
+ from ._compat import binary_streams
13
+ from ._compat import get_filesystem_encoding
14
+ from ._compat import open_stream
15
+ from ._compat import should_strip_ansi
16
+ from ._compat import strip_ansi
17
+ from ._compat import text_streams
18
+ from ._compat import WIN
19
+ from .globals import resolve_color_default
20
+
21
+ if t.TYPE_CHECKING:
22
+ import typing_extensions as te
23
+
24
+ F = t.TypeVar("F", bound=t.Callable[..., t.Any])
25
+
26
+
27
+ def _posixify(name: str) -> str:
28
+ return "-".join(name.split()).lower()
29
+
30
+
31
+ def safecall(func: F) -> F:
32
+ """Wraps a function so that it swallows exceptions."""
33
+
34
+ def wrapper(*args, **kwargs): # type: ignore
35
+ try:
36
+ return func(*args, **kwargs)
37
+ except Exception:
38
+ pass
39
+
40
+ return update_wrapper(t.cast(F, wrapper), func)
41
+
42
+
43
+ def make_str(value: t.Any) -> str:
44
+ """Converts a value into a valid string."""
45
+ if isinstance(value, bytes):
46
+ try:
47
+ return value.decode(get_filesystem_encoding())
48
+ except UnicodeError:
49
+ return value.decode("utf-8", "replace")
50
+ return str(value)
51
+
52
+
53
+ def make_default_short_help(help: str, max_length: int = 45) -> str:
54
+ """Returns a condensed version of help string."""
55
+ # Consider only the first paragraph.
56
+ paragraph_end = help.find("\n\n")
57
+
58
+ if paragraph_end != -1:
59
+ help = help[:paragraph_end]
60
+
61
+ # Collapse newlines, tabs, and spaces.
62
+ words = help.split()
63
+
64
+ if not words:
65
+ return ""
66
+
67
+ # The first paragraph started with a "no rewrap" marker, ignore it.
68
+ if words[0] == "\b":
69
+ words = words[1:]
70
+
71
+ total_length = 0
72
+ last_index = len(words) - 1
73
+
74
+ for i, word in enumerate(words):
75
+ total_length += len(word) + (i > 0)
76
+
77
+ if total_length > max_length: # too long, truncate
78
+ break
79
+
80
+ if word[-1] == ".": # sentence end, truncate without "..."
81
+ return " ".join(words[: i + 1])
82
+
83
+ if total_length == max_length and i != last_index:
84
+ break # not at sentence end, truncate with "..."
85
+ else:
86
+ return " ".join(words) # no truncation needed
87
+
88
+ # Account for the length of the suffix.
89
+ total_length += len("...")
90
+
91
+ # remove words until the length is short enough
92
+ while i > 0:
93
+ total_length -= len(words[i]) + (i > 0)
94
+
95
+ if total_length <= max_length:
96
+ break
97
+
98
+ i -= 1
99
+
100
+ return " ".join(words[:i]) + "..."
101
+
102
+
103
+ class LazyFile:
104
+ """A lazy file works like a regular file but it does not fully open
105
+ the file but it does perform some basic checks early to see if the
106
+ filename parameter does make sense. This is useful for safely opening
107
+ files for writing.
108
+ """
109
+
110
+ def __init__(
111
+ self,
112
+ filename: str,
113
+ mode: str = "r",
114
+ encoding: t.Optional[str] = None,
115
+ errors: t.Optional[str] = "strict",
116
+ atomic: bool = False,
117
+ ):
118
+ self.name = filename
119
+ self.mode = mode
120
+ self.encoding = encoding
121
+ self.errors = errors
122
+ self.atomic = atomic
123
+ self._f: t.Optional[t.IO]
124
+
125
+ if filename == "-":
126
+ self._f, self.should_close = open_stream(filename, mode, encoding, errors)
127
+ else:
128
+ if "r" in mode:
129
+ # Open and close the file in case we're opening it for
130
+ # reading so that we can catch at least some errors in
131
+ # some cases early.
132
+ open(filename, mode).close()
133
+ self._f = None
134
+ self.should_close = True
135
+
136
+ def __getattr__(self, name: str) -> t.Any:
137
+ return getattr(self.open(), name)
138
+
139
+ def __repr__(self) -> str:
140
+ if self._f is not None:
141
+ return repr(self._f)
142
+ return f"<unopened file '{self.name}' {self.mode}>"
143
+
144
+ def open(self) -> t.IO:
145
+ """Opens the file if it's not yet open. This call might fail with
146
+ a :exc:`FileError`. Not handling this error will produce an error
147
+ that Click shows.
148
+ """
149
+ if self._f is not None:
150
+ return self._f
151
+ try:
152
+ rv, self.should_close = open_stream(
153
+ self.name, self.mode, self.encoding, self.errors, atomic=self.atomic
154
+ )
155
+ except OSError as e: # noqa: E402
156
+ from .exceptions import FileError
157
+
158
+ raise FileError(self.name, hint=e.strerror) from e
159
+ self._f = rv
160
+ return rv
161
+
162
+ def close(self) -> None:
163
+ """Closes the underlying file, no matter what."""
164
+ if self._f is not None:
165
+ self._f.close()
166
+
167
+ def close_intelligently(self) -> None:
168
+ """This function only closes the file if it was opened by the lazy
169
+ file wrapper. For instance this will never close stdin.
170
+ """
171
+ if self.should_close:
172
+ self.close()
173
+
174
+ def __enter__(self) -> "LazyFile":
175
+ return self
176
+
177
+ def __exit__(self, exc_type, exc_value, tb): # type: ignore
178
+ self.close_intelligently()
179
+
180
+ def __iter__(self) -> t.Iterator[t.AnyStr]:
181
+ self.open()
182
+ return iter(self._f) # type: ignore
183
+
184
+
185
+ class KeepOpenFile:
186
+ def __init__(self, file: t.IO) -> None:
187
+ self._file = file
188
+
189
+ def __getattr__(self, name: str) -> t.Any:
190
+ return getattr(self._file, name)
191
+
192
+ def __enter__(self) -> "KeepOpenFile":
193
+ return self
194
+
195
+ def __exit__(self, exc_type, exc_value, tb): # type: ignore
196
+ pass
197
+
198
+ def __repr__(self) -> str:
199
+ return repr(self._file)
200
+
201
+ def __iter__(self) -> t.Iterator[t.AnyStr]:
202
+ return iter(self._file)
203
+
204
+
205
+ def echo(
206
+ message: t.Optional[t.Any] = None,
207
+ file: t.Optional[t.IO[t.Any]] = None,
208
+ nl: bool = True,
209
+ err: bool = False,
210
+ color: t.Optional[bool] = None,
211
+ ) -> None:
212
+ """Print a message and newline to stdout or a file. This should be
213
+ used instead of :func:`print` because it provides better support
214
+ for different data, files, and environments.
215
+
216
+ Compared to :func:`print`, this does the following:
217
+
218
+ - Ensures that the output encoding is not misconfigured on Linux.
219
+ - Supports Unicode in the Windows console.
220
+ - Supports writing to binary outputs, and supports writing bytes
221
+ to text outputs.
222
+ - Supports colors and styles on Windows.
223
+ - Removes ANSI color and style codes if the output does not look
224
+ like an interactive terminal.
225
+ - Always flushes the output.
226
+
227
+ :param message: The string or bytes to output. Other objects are
228
+ converted to strings.
229
+ :param file: The file to write to. Defaults to ``stdout``.
230
+ :param err: Write to ``stderr`` instead of ``stdout``.
231
+ :param nl: Print a newline after the message. Enabled by default.
232
+ :param color: Force showing or hiding colors and other styles. By
233
+ default Click will remove color if the output does not look like
234
+ an interactive terminal.
235
+
236
+ .. versionchanged:: 6.0
237
+ Support Unicode output on the Windows console. Click does not
238
+ modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()``
239
+ will still not support Unicode.
240
+
241
+ .. versionchanged:: 4.0
242
+ Added the ``color`` parameter.
243
+
244
+ .. versionadded:: 3.0
245
+ Added the ``err`` parameter.
246
+
247
+ .. versionchanged:: 2.0
248
+ Support colors on Windows if colorama is installed.
249
+ """
250
+ if file is None:
251
+ if err:
252
+ file = _default_text_stderr()
253
+ else:
254
+ file = _default_text_stdout()
255
+
256
+ # Convert non bytes/text into the native string type.
257
+ if message is not None and not isinstance(message, (str, bytes, bytearray)):
258
+ out: t.Optional[t.Union[str, bytes]] = str(message)
259
+ else:
260
+ out = message
261
+
262
+ if nl:
263
+ out = out or ""
264
+ if isinstance(out, str):
265
+ out += "\n"
266
+ else:
267
+ out += b"\n"
268
+
269
+ if not out:
270
+ file.flush()
271
+ return
272
+
273
+ # If there is a message and the value looks like bytes, we manually
274
+ # need to find the binary stream and write the message in there.
275
+ # This is done separately so that most stream types will work as you
276
+ # would expect. Eg: you can write to StringIO for other cases.
277
+ if isinstance(out, (bytes, bytearray)):
278
+ binary_file = _find_binary_writer(file)
279
+
280
+ if binary_file is not None:
281
+ file.flush()
282
+ binary_file.write(out)
283
+ binary_file.flush()
284
+ return
285
+
286
+ # ANSI style code support. For no message or bytes, nothing happens.
287
+ # When outputting to a file instead of a terminal, strip codes.
288
+ else:
289
+ color = resolve_color_default(color)
290
+
291
+ if should_strip_ansi(file, color):
292
+ out = strip_ansi(out)
293
+ elif WIN:
294
+ if auto_wrap_for_ansi is not None:
295
+ file = auto_wrap_for_ansi(file) # type: ignore
296
+ elif not color:
297
+ out = strip_ansi(out)
298
+
299
+ file.write(out) # type: ignore
300
+ file.flush()
301
+
302
+
303
+ def get_binary_stream(name: "te.Literal['stdin', 'stdout', 'stderr']") -> t.BinaryIO:
304
+ """Returns a system stream for byte processing.
305
+
306
+ :param name: the name of the stream to open. Valid names are ``'stdin'``,
307
+ ``'stdout'`` and ``'stderr'``
308
+ """
309
+ opener = binary_streams.get(name)
310
+ if opener is None:
311
+ raise TypeError(f"Unknown standard stream '{name}'")
312
+ return opener()
313
+
314
+
315
+ def get_text_stream(
316
+ name: "te.Literal['stdin', 'stdout', 'stderr']",
317
+ encoding: t.Optional[str] = None,
318
+ errors: t.Optional[str] = "strict",
319
+ ) -> t.TextIO:
320
+ """Returns a system stream for text processing. This usually returns
321
+ a wrapped stream around a binary stream returned from
322
+ :func:`get_binary_stream` but it also can take shortcuts for already
323
+ correctly configured streams.
324
+
325
+ :param name: the name of the stream to open. Valid names are ``'stdin'``,
326
+ ``'stdout'`` and ``'stderr'``
327
+ :param encoding: overrides the detected default encoding.
328
+ :param errors: overrides the default error mode.
329
+ """
330
+ opener = text_streams.get(name)
331
+ if opener is None:
332
+ raise TypeError(f"Unknown standard stream '{name}'")
333
+ return opener(encoding, errors)
334
+
335
+
336
+ def open_file(
337
+ filename: str,
338
+ mode: str = "r",
339
+ encoding: t.Optional[str] = None,
340
+ errors: t.Optional[str] = "strict",
341
+ lazy: bool = False,
342
+ atomic: bool = False,
343
+ ) -> t.IO:
344
+ """Open a file, with extra behavior to handle ``'-'`` to indicate
345
+ a standard stream, lazy open on write, and atomic write. Similar to
346
+ the behavior of the :class:`~click.File` param type.
347
+
348
+ If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is
349
+ wrapped so that using it in a context manager will not close it.
350
+ This makes it possible to use the function without accidentally
351
+ closing a standard stream:
352
+
353
+ .. code-block:: python
354
+
355
+ with open_file(filename) as f:
356
+ ...
357
+
358
+ :param filename: The name of the file to open, or ``'-'`` for
359
+ ``stdin``/``stdout``.
360
+ :param mode: The mode in which to open the file.
361
+ :param encoding: The encoding to decode or encode a file opened in
362
+ text mode.
363
+ :param errors: The error handling mode.
364
+ :param lazy: Wait to open the file until it is accessed. For read
365
+ mode, the file is temporarily opened to raise access errors
366
+ early, then closed until it is read again.
367
+ :param atomic: Write to a temporary file and replace the given file
368
+ on close.
369
+
370
+ .. versionadded:: 3.0
371
+ """
372
+ if lazy:
373
+ return t.cast(t.IO, LazyFile(filename, mode, encoding, errors, atomic=atomic))
374
+
375
+ f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic)
376
+
377
+ if not should_close:
378
+ f = t.cast(t.IO, KeepOpenFile(f))
379
+
380
+ return f
381
+
382
+
383
+ def format_filename(
384
+ filename: t.Union[str, bytes, os.PathLike], shorten: bool = False
385
+ ) -> str:
386
+ """Formats a filename for user display. The main purpose of this
387
+ function is to ensure that the filename can be displayed at all. This
388
+ will decode the filename to unicode if necessary in a way that it will
389
+ not fail. Optionally, it can shorten the filename to not include the
390
+ full path to the filename.
391
+
392
+ :param filename: formats a filename for UI display. This will also convert
393
+ the filename into unicode without failing.
394
+ :param shorten: this optionally shortens the filename to strip of the
395
+ path that leads up to it.
396
+ """
397
+ if shorten:
398
+ filename = os.path.basename(filename)
399
+
400
+ return os.fsdecode(filename)
401
+
402
+
403
+ def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str:
404
+ r"""Returns the config folder for the application. The default behavior
405
+ is to return whatever is most appropriate for the operating system.
406
+
407
+ To give you an idea, for an app called ``"Foo Bar"``, something like
408
+ the following folders could be returned:
409
+
410
+ Mac OS X:
411
+ ``~/Library/Application Support/Foo Bar``
412
+ Mac OS X (POSIX):
413
+ ``~/.foo-bar``
414
+ Unix:
415
+ ``~/.config/foo-bar``
416
+ Unix (POSIX):
417
+ ``~/.foo-bar``
418
+ Windows (roaming):
419
+ ``C:\Users\<user>\AppData\Roaming\Foo Bar``
420
+ Windows (not roaming):
421
+ ``C:\Users\<user>\AppData\Local\Foo Bar``
422
+
423
+ .. versionadded:: 2.0
424
+
425
+ :param app_name: the application name. This should be properly capitalized
426
+ and can contain whitespace.
427
+ :param roaming: controls if the folder should be roaming or not on Windows.
428
+ Has no affect otherwise.
429
+ :param force_posix: if this is set to `True` then on any POSIX system the
430
+ folder will be stored in the home folder with a leading
431
+ dot instead of the XDG config home or darwin's
432
+ application support folder.
433
+ """
434
+ if WIN:
435
+ key = "APPDATA" if roaming else "LOCALAPPDATA"
436
+ folder = os.environ.get(key)
437
+ if folder is None:
438
+ folder = os.path.expanduser("~")
439
+ return os.path.join(folder, app_name)
440
+ if force_posix:
441
+ return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}"))
442
+ if sys.platform == "darwin":
443
+ return os.path.join(
444
+ os.path.expanduser("~/Library/Application Support"), app_name
445
+ )
446
+ return os.path.join(
447
+ os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")),
448
+ _posixify(app_name),
449
+ )
450
+
451
+
452
+ class PacifyFlushWrapper:
453
+ """This wrapper is used to catch and suppress BrokenPipeErrors resulting
454
+ from ``.flush()`` being called on broken pipe during the shutdown/final-GC
455
+ of the Python interpreter. Notably ``.flush()`` is always called on
456
+ ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any
457
+ other cleanup code, and the case where the underlying file is not a broken
458
+ pipe, all calls and attributes are proxied.
459
+ """
460
+
461
+ def __init__(self, wrapped: t.IO) -> None:
462
+ self.wrapped = wrapped
463
+
464
+ def flush(self) -> None:
465
+ try:
466
+ self.wrapped.flush()
467
+ except OSError as e:
468
+ import errno
469
+
470
+ if e.errno != errno.EPIPE:
471
+ raise
472
+
473
+ def __getattr__(self, attr: str) -> t.Any:
474
+ return getattr(self.wrapped, attr)
475
+
476
+
477
+ def _detect_program_name(
478
+ path: t.Optional[str] = None, _main: t.Optional[ModuleType] = None
479
+ ) -> str:
480
+ """Determine the command used to run the program, for use in help
481
+ text. If a file or entry point was executed, the file name is
482
+ returned. If ``python -m`` was used to execute a module or package,
483
+ ``python -m name`` is returned.
484
+
485
+ This doesn't try to be too precise, the goal is to give a concise
486
+ name for help text. Files are only shown as their name without the
487
+ path. ``python`` is only shown for modules, and the full path to
488
+ ``sys.executable`` is not shown.
489
+
490
+ :param path: The Python file being executed. Python puts this in
491
+ ``sys.argv[0]``, which is used by default.
492
+ :param _main: The ``__main__`` module. This should only be passed
493
+ during internal testing.
494
+
495
+ .. versionadded:: 8.0
496
+ Based on command args detection in the Werkzeug reloader.
497
+
498
+ :meta private:
499
+ """
500
+ if _main is None:
501
+ _main = sys.modules["__main__"]
502
+
503
+ if not path:
504
+ path = sys.argv[0]
505
+
506
+ # The value of __package__ indicates how Python was called. It may
507
+ # not exist if a setuptools script is installed as an egg. It may be
508
+ # set incorrectly for entry points created with pip on Windows.
509
+ if getattr(_main, "__package__", None) is None or (
510
+ os.name == "nt"
511
+ and _main.__package__ == ""
512
+ and not os.path.exists(path)
513
+ and os.path.exists(f"{path}.exe")
514
+ ):
515
+ # Executed a file, like "python app.py".
516
+ return os.path.basename(path)
517
+
518
+ # Executed a module, like "python -m example".
519
+ # Rewritten by Python from "-m script" to "/path/to/script.py".
520
+ # Need to look at main module to determine how it was executed.
521
+ py_module = t.cast(str, _main.__package__)
522
+ name = os.path.splitext(os.path.basename(path))[0]
523
+
524
+ # A submodule like "example.cli".
525
+ if name != "__main__":
526
+ py_module = f"{py_module}.{name}"
527
+
528
+ return f"python -m {py_module.lstrip('.')}"
529
+
530
+
531
+ def _expand_args(
532
+ args: t.Iterable[str],
533
+ *,
534
+ user: bool = True,
535
+ env: bool = True,
536
+ glob_recursive: bool = True,
537
+ ) -> t.List[str]:
538
+ """Simulate Unix shell expansion with Python functions.
539
+
540
+ See :func:`glob.glob`, :func:`os.path.expanduser`, and
541
+ :func:`os.path.expandvars`.
542
+
543
+ This is intended for use on Windows, where the shell does not do any
544
+ expansion. It may not exactly match what a Unix shell would do.
545
+
546
+ :param args: List of command line arguments to expand.
547
+ :param user: Expand user home directory.
548
+ :param env: Expand environment variables.
549
+ :param glob_recursive: ``**`` matches directories recursively.
550
+
551
+ .. versionchanged:: 8.1
552
+ Invalid glob patterns are treated as empty expansions rather
553
+ than raising an error.
554
+
555
+ .. versionadded:: 8.0
556
+
557
+ :meta private:
558
+ """
559
+ from glob import glob
560
+
561
+ out = []
562
+
563
+ for arg in args:
564
+ if user:
565
+ arg = os.path.expanduser(arg)
566
+
567
+ if env:
568
+ arg = os.path.expandvars(arg)
569
+
570
+ try:
571
+ matches = glob(arg, recursive=glob_recursive)
572
+ except re.error:
573
+ matches = []
574
+
575
+ if not matches:
576
+ out.append(arg)
577
+ else:
578
+ out.extend(matches)
579
+
580
+ return out
@@ -0,0 +1,28 @@
1
+ Copyright 2014 Pallets
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are
5
+ met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of the copyright holder nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,2 @@
1
+ PyYAML==6.0.1
2
+ click==8.1.3