from typing import overload
@overload
def joinpath(*path_pieces: str) -> str: ...
@overload
def joinpath(*path_pieces: list[str] | str) -> list[str]: ...
def joinpath(*path_pieces: list[str] | str) -> list[str] | str:
"""Join paths.
os separators in the path pieces will be remove, except for the trailing
separator of the last piece which is used to differenciate folders from
files.
Parameters
----------
*path_pieces : str | list[str]
Path pieces to join. If one of the path piece is a list, the function
will join each element of the list with the other path pieces and return
a list of path. If all path pieces are strings, the function will return
a string.
Returns
-------
str | list[str]
the joined path: str if all the components are strings, list of strings
otherwise.
Examples
--------
>>> joinpath("a", "b", "c")
"a/b/c"
>>> joinpath("a", "", "c")
"a/c"
>>> joinpath(["a", "b"], "c/")
["a/c/", "b/c/"]
>>> joinpath(["a", "b"], ["c", "d"], "e")
["a/c/e", "a/d/e", "b/c/e", "b/d/e"]
>>> joinpath(["a", "", "b"], ["c", "d"], "e")
["a/c/e", "a/d/e", "b/c/e", "b/d/e"]
"""
if all(isinstance(piece, str) for piece in path_pieces):
return join_path_pieces(*path_pieces)
if len(path_pieces) < 2:
raise ValueError("At least two path pieces are required.")
if len(path_pieces) > 2:
# Recursive call to join the first two pieces and the rest of the pieces.
# This will slowly reduce the number of pieces until there are only two.
return joinpath(joinpath(path_pieces[0], path_pieces[1]), *path_pieces[2:])
first_paths = ensure_in_list(path_pieces[0])
second_paths = ensure_in_list(path_pieces[1])
joined_paths = _cartesian_product_join_paths(first_paths, second_paths)
return joined_paths
def join_path_pieces(*path_pieces: str) -> str:
"""Join path pieces, while stripping leading slashes for all except the first,
and trailing slashes for all except the last.
"""
striped_pieces = [path for path in path_pieces if path != ""]
for i in range(len(striped_pieces) - 1):
striped_pieces = striped_pieces.rstrip("/")
for i in range(1, len(striped_pieces)):
striped_pieces = striped_pieces.lstrip("/")
return os.sep.join(striped_pieces)
def ensure_in_list(value: T | list[T]) -> list[T]:
"""Put in a list any scalar value that is not None.
If it is already a list, do nothing.
"""
if value is not None and not isinstance(value, list):
value = [value]
return value
def _cartesian_product_join_paths(
first_path_piece: list[str], second_path_piece: list[str]
) -> list[str]:
"""Compute the cartesian product of two lists of paths.
If one of the path piece is an empty string, it will be ignored.
The output list will contain the concatenation of each element of the first
list with each element of the second list.
Returns
-------
list[str]
List of length len(first_path_piece) * len(second_path_piece) that
contains the concatenated path.
"""
...
< /code>
К сожалению, есть две ошибки Mypy: < /p>
- Ошибка L4: подписи перегруженных функций 1 и 2 перекрываются с несовместимыми типами возврата < /li>
Ошибка L40: аргумент 1 к "join_path_pieces" имеет невозможный тип "*tuple. Ожидаемый "str"
для первой ошибки эти две подписи предназначены для того, чтобы отразить, что если есть по крайней мере один список STR в качестве ввода, вывод будет списком.>
Подробнее здесь: https://stackoverflow.com/questions/796 ... -unpacking