up follow livre
This commit is contained in:
		
							parent
							
								
									b4b4398bb0
								
							
						
					
					
						commit
						3a7a3849ae
					
				
					 12242 changed files with 2564461 additions and 6914 deletions
				
			
		
							
								
								
									
										627
									
								
								venv/lib/python3.13/site-packages/click/utils.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										627
									
								
								venv/lib/python3.13/site-packages/click/utils.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,627 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import collections.abc as cabc | ||||
| import os | ||||
| import re | ||||
| import sys | ||||
| import typing as t | ||||
| from functools import update_wrapper | ||||
| from types import ModuleType | ||||
| from types import TracebackType | ||||
| 
 | ||||
| from ._compat import _default_text_stderr | ||||
| from ._compat import _default_text_stdout | ||||
| from ._compat import _find_binary_writer | ||||
| from ._compat import auto_wrap_for_ansi | ||||
| from ._compat import binary_streams | ||||
| from ._compat import open_stream | ||||
| from ._compat import should_strip_ansi | ||||
| from ._compat import strip_ansi | ||||
| from ._compat import text_streams | ||||
| from ._compat import WIN | ||||
| from .globals import resolve_color_default | ||||
| 
 | ||||
| if t.TYPE_CHECKING: | ||||
|     import typing_extensions as te | ||||
| 
 | ||||
|     P = te.ParamSpec("P") | ||||
| 
 | ||||
| R = t.TypeVar("R") | ||||
| 
 | ||||
| 
 | ||||
| def _posixify(name: str) -> str: | ||||
|     return "-".join(name.split()).lower() | ||||
| 
 | ||||
| 
 | ||||
| def safecall(func: t.Callable[P, R]) -> t.Callable[P, R | None]: | ||||
|     """Wraps a function so that it swallows exceptions.""" | ||||
| 
 | ||||
|     def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None: | ||||
|         try: | ||||
|             return func(*args, **kwargs) | ||||
|         except Exception: | ||||
|             pass | ||||
|         return None | ||||
| 
 | ||||
|     return update_wrapper(wrapper, func) | ||||
| 
 | ||||
| 
 | ||||
| def make_str(value: t.Any) -> str: | ||||
|     """Converts a value into a valid string.""" | ||||
|     if isinstance(value, bytes): | ||||
|         try: | ||||
|             return value.decode(sys.getfilesystemencoding()) | ||||
|         except UnicodeError: | ||||
|             return value.decode("utf-8", "replace") | ||||
|     return str(value) | ||||
| 
 | ||||
| 
 | ||||
| def make_default_short_help(help: str, max_length: int = 45) -> str: | ||||
|     """Returns a condensed version of help string.""" | ||||
|     # Consider only the first paragraph. | ||||
|     paragraph_end = help.find("\n\n") | ||||
| 
 | ||||
|     if paragraph_end != -1: | ||||
|         help = help[:paragraph_end] | ||||
| 
 | ||||
|     # Collapse newlines, tabs, and spaces. | ||||
|     words = help.split() | ||||
| 
 | ||||
|     if not words: | ||||
|         return "" | ||||
| 
 | ||||
|     # The first paragraph started with a "no rewrap" marker, ignore it. | ||||
|     if words[0] == "\b": | ||||
|         words = words[1:] | ||||
| 
 | ||||
|     total_length = 0 | ||||
|     last_index = len(words) - 1 | ||||
| 
 | ||||
|     for i, word in enumerate(words): | ||||
|         total_length += len(word) + (i > 0) | ||||
| 
 | ||||
|         if total_length > max_length:  # too long, truncate | ||||
|             break | ||||
| 
 | ||||
|         if word[-1] == ".":  # sentence end, truncate without "..." | ||||
|             return " ".join(words[: i + 1]) | ||||
| 
 | ||||
|         if total_length == max_length and i != last_index: | ||||
|             break  # not at sentence end, truncate with "..." | ||||
|     else: | ||||
|         return " ".join(words)  # no truncation needed | ||||
| 
 | ||||
|     # Account for the length of the suffix. | ||||
|     total_length += len("...") | ||||
| 
 | ||||
|     # remove words until the length is short enough | ||||
|     while i > 0: | ||||
|         total_length -= len(words[i]) + (i > 0) | ||||
| 
 | ||||
|         if total_length <= max_length: | ||||
|             break | ||||
| 
 | ||||
|         i -= 1 | ||||
| 
 | ||||
|     return " ".join(words[:i]) + "..." | ||||
| 
 | ||||
| 
 | ||||
| class LazyFile: | ||||
|     """A lazy file works like a regular file but it does not fully open | ||||
|     the file but it does perform some basic checks early to see if the | ||||
|     filename parameter does make sense.  This is useful for safely opening | ||||
|     files for writing. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__( | ||||
|         self, | ||||
|         filename: str | os.PathLike[str], | ||||
|         mode: str = "r", | ||||
|         encoding: str | None = None, | ||||
|         errors: str | None = "strict", | ||||
|         atomic: bool = False, | ||||
|     ): | ||||
|         self.name: str = os.fspath(filename) | ||||
|         self.mode = mode | ||||
|         self.encoding = encoding | ||||
|         self.errors = errors | ||||
|         self.atomic = atomic | ||||
|         self._f: t.IO[t.Any] | None | ||||
|         self.should_close: bool | ||||
| 
 | ||||
|         if self.name == "-": | ||||
|             self._f, self.should_close = open_stream(filename, mode, encoding, errors) | ||||
|         else: | ||||
|             if "r" in mode: | ||||
|                 # Open and close the file in case we're opening it for | ||||
|                 # reading so that we can catch at least some errors in | ||||
|                 # some cases early. | ||||
|                 open(filename, mode).close() | ||||
|             self._f = None | ||||
|             self.should_close = True | ||||
| 
 | ||||
|     def __getattr__(self, name: str) -> t.Any: | ||||
|         return getattr(self.open(), name) | ||||
| 
 | ||||
|     def __repr__(self) -> str: | ||||
|         if self._f is not None: | ||||
|             return repr(self._f) | ||||
|         return f"<unopened file '{format_filename(self.name)}' {self.mode}>" | ||||
| 
 | ||||
|     def open(self) -> t.IO[t.Any]: | ||||
|         """Opens the file if it's not yet open.  This call might fail with | ||||
|         a :exc:`FileError`.  Not handling this error will produce an error | ||||
|         that Click shows. | ||||
|         """ | ||||
|         if self._f is not None: | ||||
|             return self._f | ||||
|         try: | ||||
|             rv, self.should_close = open_stream( | ||||
|                 self.name, self.mode, self.encoding, self.errors, atomic=self.atomic | ||||
|             ) | ||||
|         except OSError as e: | ||||
|             from .exceptions import FileError | ||||
| 
 | ||||
|             raise FileError(self.name, hint=e.strerror) from e | ||||
|         self._f = rv | ||||
|         return rv | ||||
| 
 | ||||
|     def close(self) -> None: | ||||
|         """Closes the underlying file, no matter what.""" | ||||
|         if self._f is not None: | ||||
|             self._f.close() | ||||
| 
 | ||||
|     def close_intelligently(self) -> None: | ||||
|         """This function only closes the file if it was opened by the lazy | ||||
|         file wrapper.  For instance this will never close stdin. | ||||
|         """ | ||||
|         if self.should_close: | ||||
|             self.close() | ||||
| 
 | ||||
|     def __enter__(self) -> LazyFile: | ||||
|         return self | ||||
| 
 | ||||
|     def __exit__( | ||||
|         self, | ||||
|         exc_type: type[BaseException] | None, | ||||
|         exc_value: BaseException | None, | ||||
|         tb: TracebackType | None, | ||||
|     ) -> None: | ||||
|         self.close_intelligently() | ||||
| 
 | ||||
|     def __iter__(self) -> cabc.Iterator[t.AnyStr]: | ||||
|         self.open() | ||||
|         return iter(self._f)  # type: ignore | ||||
| 
 | ||||
| 
 | ||||
| class KeepOpenFile: | ||||
|     def __init__(self, file: t.IO[t.Any]) -> None: | ||||
|         self._file: t.IO[t.Any] = file | ||||
| 
 | ||||
|     def __getattr__(self, name: str) -> t.Any: | ||||
|         return getattr(self._file, name) | ||||
| 
 | ||||
|     def __enter__(self) -> KeepOpenFile: | ||||
|         return self | ||||
| 
 | ||||
|     def __exit__( | ||||
|         self, | ||||
|         exc_type: type[BaseException] | None, | ||||
|         exc_value: BaseException | None, | ||||
|         tb: TracebackType | None, | ||||
|     ) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def __repr__(self) -> str: | ||||
|         return repr(self._file) | ||||
| 
 | ||||
|     def __iter__(self) -> cabc.Iterator[t.AnyStr]: | ||||
|         return iter(self._file) | ||||
| 
 | ||||
| 
 | ||||
| def echo( | ||||
|     message: t.Any | None = None, | ||||
|     file: t.IO[t.Any] | None = None, | ||||
|     nl: bool = True, | ||||
|     err: bool = False, | ||||
|     color: bool | None = None, | ||||
| ) -> None: | ||||
|     """Print a message and newline to stdout or a file. This should be | ||||
|     used instead of :func:`print` because it provides better support | ||||
|     for different data, files, and environments. | ||||
| 
 | ||||
|     Compared to :func:`print`, this does the following: | ||||
| 
 | ||||
|     -   Ensures that the output encoding is not misconfigured on Linux. | ||||
|     -   Supports Unicode in the Windows console. | ||||
|     -   Supports writing to binary outputs, and supports writing bytes | ||||
|         to text outputs. | ||||
|     -   Supports colors and styles on Windows. | ||||
|     -   Removes ANSI color and style codes if the output does not look | ||||
|         like an interactive terminal. | ||||
|     -   Always flushes the output. | ||||
| 
 | ||||
|     :param message: The string or bytes to output. Other objects are | ||||
|         converted to strings. | ||||
|     :param file: The file to write to. Defaults to ``stdout``. | ||||
|     :param err: Write to ``stderr`` instead of ``stdout``. | ||||
|     :param nl: Print a newline after the message. Enabled by default. | ||||
|     :param color: Force showing or hiding colors and other styles. By | ||||
|         default Click will remove color if the output does not look like | ||||
|         an interactive terminal. | ||||
| 
 | ||||
|     .. versionchanged:: 6.0 | ||||
|         Support Unicode output on the Windows console. Click does not | ||||
|         modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` | ||||
|         will still not support Unicode. | ||||
| 
 | ||||
|     .. versionchanged:: 4.0 | ||||
|         Added the ``color`` parameter. | ||||
| 
 | ||||
|     .. versionadded:: 3.0 | ||||
|         Added the ``err`` parameter. | ||||
| 
 | ||||
|     .. versionchanged:: 2.0 | ||||
|         Support colors on Windows if colorama is installed. | ||||
|     """ | ||||
|     if file is None: | ||||
|         if err: | ||||
|             file = _default_text_stderr() | ||||
|         else: | ||||
|             file = _default_text_stdout() | ||||
| 
 | ||||
|         # There are no standard streams attached to write to. For example, | ||||
|         # pythonw on Windows. | ||||
|         if file is None: | ||||
|             return | ||||
| 
 | ||||
|     # Convert non bytes/text into the native string type. | ||||
|     if message is not None and not isinstance(message, (str, bytes, bytearray)): | ||||
|         out: str | bytes | None = str(message) | ||||
|     else: | ||||
|         out = message | ||||
| 
 | ||||
|     if nl: | ||||
|         out = out or "" | ||||
|         if isinstance(out, str): | ||||
|             out += "\n" | ||||
|         else: | ||||
|             out += b"\n" | ||||
| 
 | ||||
|     if not out: | ||||
|         file.flush() | ||||
|         return | ||||
| 
 | ||||
|     # If there is a message and the value looks like bytes, we manually | ||||
|     # need to find the binary stream and write the message in there. | ||||
|     # This is done separately so that most stream types will work as you | ||||
|     # would expect. Eg: you can write to StringIO for other cases. | ||||
|     if isinstance(out, (bytes, bytearray)): | ||||
|         binary_file = _find_binary_writer(file) | ||||
| 
 | ||||
|         if binary_file is not None: | ||||
|             file.flush() | ||||
|             binary_file.write(out) | ||||
|             binary_file.flush() | ||||
|             return | ||||
| 
 | ||||
|     # ANSI style code support. For no message or bytes, nothing happens. | ||||
|     # When outputting to a file instead of a terminal, strip codes. | ||||
|     else: | ||||
|         color = resolve_color_default(color) | ||||
| 
 | ||||
|         if should_strip_ansi(file, color): | ||||
|             out = strip_ansi(out) | ||||
|         elif WIN: | ||||
|             if auto_wrap_for_ansi is not None: | ||||
|                 file = auto_wrap_for_ansi(file, color)  # type: ignore | ||||
|             elif not color: | ||||
|                 out = strip_ansi(out) | ||||
| 
 | ||||
|     file.write(out)  # type: ignore | ||||
|     file.flush() | ||||
| 
 | ||||
| 
 | ||||
| def get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryIO: | ||||
|     """Returns a system stream for byte processing. | ||||
| 
 | ||||
|     :param name: the name of the stream to open.  Valid names are ``'stdin'``, | ||||
|                  ``'stdout'`` and ``'stderr'`` | ||||
|     """ | ||||
|     opener = binary_streams.get(name) | ||||
|     if opener is None: | ||||
|         raise TypeError(f"Unknown standard stream '{name}'") | ||||
|     return opener() | ||||
| 
 | ||||
| 
 | ||||
| def get_text_stream( | ||||
|     name: t.Literal["stdin", "stdout", "stderr"], | ||||
|     encoding: str | None = None, | ||||
|     errors: str | None = "strict", | ||||
| ) -> t.TextIO: | ||||
|     """Returns a system stream for text processing.  This usually returns | ||||
|     a wrapped stream around a binary stream returned from | ||||
|     :func:`get_binary_stream` but it also can take shortcuts for already | ||||
|     correctly configured streams. | ||||
| 
 | ||||
|     :param name: the name of the stream to open.  Valid names are ``'stdin'``, | ||||
|                  ``'stdout'`` and ``'stderr'`` | ||||
|     :param encoding: overrides the detected default encoding. | ||||
|     :param errors: overrides the default error mode. | ||||
|     """ | ||||
|     opener = text_streams.get(name) | ||||
|     if opener is None: | ||||
|         raise TypeError(f"Unknown standard stream '{name}'") | ||||
|     return opener(encoding, errors) | ||||
| 
 | ||||
| 
 | ||||
| def open_file( | ||||
|     filename: str | os.PathLike[str], | ||||
|     mode: str = "r", | ||||
|     encoding: str | None = None, | ||||
|     errors: str | None = "strict", | ||||
|     lazy: bool = False, | ||||
|     atomic: bool = False, | ||||
| ) -> t.IO[t.Any]: | ||||
|     """Open a file, with extra behavior to handle ``'-'`` to indicate | ||||
|     a standard stream, lazy open on write, and atomic write. Similar to | ||||
|     the behavior of the :class:`~click.File` param type. | ||||
| 
 | ||||
|     If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is | ||||
|     wrapped so that using it in a context manager will not close it. | ||||
|     This makes it possible to use the function without accidentally | ||||
|     closing a standard stream: | ||||
| 
 | ||||
|     .. code-block:: python | ||||
| 
 | ||||
|         with open_file(filename) as f: | ||||
|             ... | ||||
| 
 | ||||
|     :param filename: The name or Path of the file to open, or ``'-'`` for | ||||
|         ``stdin``/``stdout``. | ||||
|     :param mode: The mode in which to open the file. | ||||
|     :param encoding: The encoding to decode or encode a file opened in | ||||
|         text mode. | ||||
|     :param errors: The error handling mode. | ||||
|     :param lazy: Wait to open the file until it is accessed. For read | ||||
|         mode, the file is temporarily opened to raise access errors | ||||
|         early, then closed until it is read again. | ||||
|     :param atomic: Write to a temporary file and replace the given file | ||||
|         on close. | ||||
| 
 | ||||
|     .. versionadded:: 3.0 | ||||
|     """ | ||||
|     if lazy: | ||||
|         return t.cast( | ||||
|             "t.IO[t.Any]", LazyFile(filename, mode, encoding, errors, atomic=atomic) | ||||
|         ) | ||||
| 
 | ||||
|     f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) | ||||
| 
 | ||||
|     if not should_close: | ||||
|         f = t.cast("t.IO[t.Any]", KeepOpenFile(f)) | ||||
| 
 | ||||
|     return f | ||||
| 
 | ||||
| 
 | ||||
| def format_filename( | ||||
|     filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], | ||||
|     shorten: bool = False, | ||||
| ) -> str: | ||||
|     """Format a filename as a string for display. Ensures the filename can be | ||||
|     displayed by replacing any invalid bytes or surrogate escapes in the name | ||||
|     with the replacement character ``<EFBFBD>``. | ||||
| 
 | ||||
|     Invalid bytes or surrogate escapes will raise an error when written to a | ||||
|     stream with ``errors="strict"``. This will typically happen with ``stdout`` | ||||
|     when the locale is something like ``en_GB.UTF-8``. | ||||
| 
 | ||||
|     Many scenarios *are* safe to write surrogates though, due to PEP 538 and | ||||
|     PEP 540, including: | ||||
| 
 | ||||
|     -   Writing to ``stderr``, which uses ``errors="backslashreplace"``. | ||||
|     -   The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens | ||||
|         stdout and stderr with ``errors="surrogateescape"``. | ||||
|     -   None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. | ||||
|     -   Python is started in UTF-8 mode  with  ``PYTHONUTF8=1`` or ``-X utf8``. | ||||
|         Python opens stdout and stderr with ``errors="surrogateescape"``. | ||||
| 
 | ||||
|     :param filename: formats a filename for UI display.  This will also convert | ||||
|                      the filename into unicode without failing. | ||||
|     :param shorten: this optionally shortens the filename to strip of the | ||||
|                     path that leads up to it. | ||||
|     """ | ||||
|     if shorten: | ||||
|         filename = os.path.basename(filename) | ||||
|     else: | ||||
|         filename = os.fspath(filename) | ||||
| 
 | ||||
|     if isinstance(filename, bytes): | ||||
|         filename = filename.decode(sys.getfilesystemencoding(), "replace") | ||||
|     else: | ||||
|         filename = filename.encode("utf-8", "surrogateescape").decode( | ||||
|             "utf-8", "replace" | ||||
|         ) | ||||
| 
 | ||||
|     return filename | ||||
| 
 | ||||
| 
 | ||||
| def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: | ||||
|     r"""Returns the config folder for the application.  The default behavior | ||||
|     is to return whatever is most appropriate for the operating system. | ||||
| 
 | ||||
|     To give you an idea, for an app called ``"Foo Bar"``, something like | ||||
|     the following folders could be returned: | ||||
| 
 | ||||
|     Mac OS X: | ||||
|       ``~/Library/Application Support/Foo Bar`` | ||||
|     Mac OS X (POSIX): | ||||
|       ``~/.foo-bar`` | ||||
|     Unix: | ||||
|       ``~/.config/foo-bar`` | ||||
|     Unix (POSIX): | ||||
|       ``~/.foo-bar`` | ||||
|     Windows (roaming): | ||||
|       ``C:\Users\<user>\AppData\Roaming\Foo Bar`` | ||||
|     Windows (not roaming): | ||||
|       ``C:\Users\<user>\AppData\Local\Foo Bar`` | ||||
| 
 | ||||
|     .. versionadded:: 2.0 | ||||
| 
 | ||||
|     :param app_name: the application name.  This should be properly capitalized | ||||
|                      and can contain whitespace. | ||||
|     :param roaming: controls if the folder should be roaming or not on Windows. | ||||
|                     Has no effect otherwise. | ||||
|     :param force_posix: if this is set to `True` then on any POSIX system the | ||||
|                         folder will be stored in the home folder with a leading | ||||
|                         dot instead of the XDG config home or darwin's | ||||
|                         application support folder. | ||||
|     """ | ||||
|     if WIN: | ||||
|         key = "APPDATA" if roaming else "LOCALAPPDATA" | ||||
|         folder = os.environ.get(key) | ||||
|         if folder is None: | ||||
|             folder = os.path.expanduser("~") | ||||
|         return os.path.join(folder, app_name) | ||||
|     if force_posix: | ||||
|         return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) | ||||
|     if sys.platform == "darwin": | ||||
|         return os.path.join( | ||||
|             os.path.expanduser("~/Library/Application Support"), app_name | ||||
|         ) | ||||
|     return os.path.join( | ||||
|         os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), | ||||
|         _posixify(app_name), | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class PacifyFlushWrapper: | ||||
|     """This wrapper is used to catch and suppress BrokenPipeErrors resulting | ||||
|     from ``.flush()`` being called on broken pipe during the shutdown/final-GC | ||||
|     of the Python interpreter. Notably ``.flush()`` is always called on | ||||
|     ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any | ||||
|     other cleanup code, and the case where the underlying file is not a broken | ||||
|     pipe, all calls and attributes are proxied. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, wrapped: t.IO[t.Any]) -> None: | ||||
|         self.wrapped = wrapped | ||||
| 
 | ||||
|     def flush(self) -> None: | ||||
|         try: | ||||
|             self.wrapped.flush() | ||||
|         except OSError as e: | ||||
|             import errno | ||||
| 
 | ||||
|             if e.errno != errno.EPIPE: | ||||
|                 raise | ||||
| 
 | ||||
|     def __getattr__(self, attr: str) -> t.Any: | ||||
|         return getattr(self.wrapped, attr) | ||||
| 
 | ||||
| 
 | ||||
| def _detect_program_name( | ||||
|     path: str | None = None, _main: ModuleType | None = None | ||||
| ) -> str: | ||||
|     """Determine the command used to run the program, for use in help | ||||
|     text. If a file or entry point was executed, the file name is | ||||
|     returned. If ``python -m`` was used to execute a module or package, | ||||
|     ``python -m name`` is returned. | ||||
| 
 | ||||
|     This doesn't try to be too precise, the goal is to give a concise | ||||
|     name for help text. Files are only shown as their name without the | ||||
|     path. ``python`` is only shown for modules, and the full path to | ||||
|     ``sys.executable`` is not shown. | ||||
| 
 | ||||
|     :param path: The Python file being executed. Python puts this in | ||||
|         ``sys.argv[0]``, which is used by default. | ||||
|     :param _main: The ``__main__`` module. This should only be passed | ||||
|         during internal testing. | ||||
| 
 | ||||
|     .. versionadded:: 8.0 | ||||
|         Based on command args detection in the Werkzeug reloader. | ||||
| 
 | ||||
|     :meta private: | ||||
|     """ | ||||
|     if _main is None: | ||||
|         _main = sys.modules["__main__"] | ||||
| 
 | ||||
|     if not path: | ||||
|         path = sys.argv[0] | ||||
| 
 | ||||
|     # The value of __package__ indicates how Python was called. It may | ||||
|     # not exist if a setuptools script is installed as an egg. It may be | ||||
|     # set incorrectly for entry points created with pip on Windows. | ||||
|     # It is set to "" inside a Shiv or PEX zipapp. | ||||
|     if getattr(_main, "__package__", None) in {None, ""} or ( | ||||
|         os.name == "nt" | ||||
|         and _main.__package__ == "" | ||||
|         and not os.path.exists(path) | ||||
|         and os.path.exists(f"{path}.exe") | ||||
|     ): | ||||
|         # Executed a file, like "python app.py". | ||||
|         return os.path.basename(path) | ||||
| 
 | ||||
|     # Executed a module, like "python -m example". | ||||
|     # Rewritten by Python from "-m script" to "/path/to/script.py". | ||||
|     # Need to look at main module to determine how it was executed. | ||||
|     py_module = t.cast(str, _main.__package__) | ||||
|     name = os.path.splitext(os.path.basename(path))[0] | ||||
| 
 | ||||
|     # A submodule like "example.cli". | ||||
|     if name != "__main__": | ||||
|         py_module = f"{py_module}.{name}" | ||||
| 
 | ||||
|     return f"python -m {py_module.lstrip('.')}" | ||||
| 
 | ||||
| 
 | ||||
| def _expand_args( | ||||
|     args: cabc.Iterable[str], | ||||
|     *, | ||||
|     user: bool = True, | ||||
|     env: bool = True, | ||||
|     glob_recursive: bool = True, | ||||
| ) -> list[str]: | ||||
|     """Simulate Unix shell expansion with Python functions. | ||||
| 
 | ||||
|     See :func:`glob.glob`, :func:`os.path.expanduser`, and | ||||
|     :func:`os.path.expandvars`. | ||||
| 
 | ||||
|     This is intended for use on Windows, where the shell does not do any | ||||
|     expansion. It may not exactly match what a Unix shell would do. | ||||
| 
 | ||||
|     :param args: List of command line arguments to expand. | ||||
|     :param user: Expand user home directory. | ||||
|     :param env: Expand environment variables. | ||||
|     :param glob_recursive: ``**`` matches directories recursively. | ||||
| 
 | ||||
|     .. versionchanged:: 8.1 | ||||
|         Invalid glob patterns are treated as empty expansions rather | ||||
|         than raising an error. | ||||
| 
 | ||||
|     .. versionadded:: 8.0 | ||||
| 
 | ||||
|     :meta private: | ||||
|     """ | ||||
|     from glob import glob | ||||
| 
 | ||||
|     out = [] | ||||
| 
 | ||||
|     for arg in args: | ||||
|         if user: | ||||
|             arg = os.path.expanduser(arg) | ||||
| 
 | ||||
|         if env: | ||||
|             arg = os.path.expandvars(arg) | ||||
| 
 | ||||
|         try: | ||||
|             matches = glob(arg, recursive=glob_recursive) | ||||
|         except re.error: | ||||
|             matches = [] | ||||
| 
 | ||||
|         if not matches: | ||||
|             out.append(arg) | ||||
|         else: | ||||
|             out.extend(matches) | ||||
| 
 | ||||
|     return out | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tykayn
						Tykayn