Module wslPath.main

Expand source code
from __future__ import annotations

import re
from pathlib import Path, WindowsPath
"""Convert between Linux and Windows path in WSL (Windows Subsystem for Linux).
"""

def is_windows_path(path: str | Path) -> bool:
    """Determine if the given path is in Windows format."""
    path = str(path)
    # Check for the current directory
    if path == ".":
        return True
    # Check for drive letter and backslashes
    return bool(re.match(r'^[A-Za-z]:\\', path)) or '\\' in path


def is_posix_path(path: str | Path) -> bool:
    """Determine if the given path is in POSIX format."""
    path = str(path)
    # Check for the current directory
    if path == ".":
        return True
    return '/' in path and not '\\' in path


def has_invalid_windows_path_chars(path: str | Path) -> bool:
    """Check if the given path contains invalid Windows path characters."""
    path = str(path)
    # Check for invalid characters in filenames or directory names
    invalid_chars_pattern = re.compile(r'[\^<>"|?*]')
    invalid_backslash = re.compile(r'(?<=[^A-Za-z0-9]):|:(?=[^\\])')
    ascii_control_chars = any(ord(char) < 32 for char in path)
    invalid_colon = re.search(r'^(?![A-Za-z]:\\).*:', path)
    return bool(
        invalid_chars_pattern.search(path) or
        ascii_control_chars or
        invalid_colon or
        invalid_backslash.search(path)
    )

###########################################################
# main
###########################################################

def to_posix(path: str | Path) -> str | Path:
    """Convert a Windows path to a POSIX path
    Examples:
        >>> import wslPath
        >>> pathwin = "hoge\\fuga"
        >>> wslPath.to_posix(pathwin)
        hoge/fuga

        >>> pathwin = "C:\\hoge\\fuga"
        >>> wslPath.to_posix(pathwin)
        /mnt/c/hoge/fuga
    """
    flag_path = isinstance(path, Path)
    path = str(path)
    if not is_windows_path(path):
        raise ValueError(f"{path} is an invalid Windows path")

    # Remove consecutive backslashes
    path = re.sub(r"\\\\+", r"\\", path)
    path = path.replace("\\", "/")

    # Convert drive letter to POSIX format
    drive_pattern = re.compile(r"^([A-Z]):/")
    if drive_pattern.search(path):
        drive, directory = path.split(":/", 1)
        drive = drive.lower()
        path = f"/mnt/{drive}/{directory}"

    if flag_path:
        path = Path(path)

    return path


def to_windows(path: str | Path) -> str | Path:
    """Convert a POSIX path to a Windows path
    Examples:
    >>> import wslPath
    >>> pathposix = "hoge/fuga"
    >>> wslPath.to_windows(pathposix)
    hoge\\fuga

    >>> pathposix = "/mnt/c/hoge/fuga"
    >>> wslPath.to_windows(pathposix)
    C:\\hoge\\fuga
    """
    flag_path = isinstance(path, Path)

    if has_invalid_windows_path_chars(path):
        raise ValueError(f"{path} includes invalid filepath characters on Windows")


    if not is_posix_path(path) and not isinstance(path, WindowsPath):
        raise ValueError(f"{path} is not a POSIX path")

    # Normalize slashes
    path = str(path).replace("\\", "/")
    path = re.sub(r"/+", "/", path)

    # Convert /mnt/c/ style paths to C:\
    if path.startswith("/mnt/"):
        drive_letter = path[5].upper()
        path = drive_letter + ":" + path[6:]

    path = path.replace("/", "\\")

    if flag_path:
        path = Path(path)

    return path

Functions

def has_invalid_windows_path_chars(path: str | Path) ‑> bool

Check if the given path contains invalid Windows path characters.

Expand source code
def has_invalid_windows_path_chars(path: str | Path) -> bool:
    """Check if the given path contains invalid Windows path characters."""
    path = str(path)
    # Check for invalid characters in filenames or directory names
    invalid_chars_pattern = re.compile(r'[\^<>"|?*]')
    invalid_backslash = re.compile(r'(?<=[^A-Za-z0-9]):|:(?=[^\\])')
    ascii_control_chars = any(ord(char) < 32 for char in path)
    invalid_colon = re.search(r'^(?![A-Za-z]:\\).*:', path)
    return bool(
        invalid_chars_pattern.search(path) or
        ascii_control_chars or
        invalid_colon or
        invalid_backslash.search(path)
    )
def is_posix_path(path: str | Path) ‑> bool

Determine if the given path is in POSIX format.

Expand source code
def is_posix_path(path: str | Path) -> bool:
    """Determine if the given path is in POSIX format."""
    path = str(path)
    # Check for the current directory
    if path == ".":
        return True
    return '/' in path and not '\\' in path
def is_windows_path(path: str | Path) ‑> bool

Determine if the given path is in Windows format.

Expand source code
def is_windows_path(path: str | Path) -> bool:
    """Determine if the given path is in Windows format."""
    path = str(path)
    # Check for the current directory
    if path == ".":
        return True
    # Check for drive letter and backslashes
    return bool(re.match(r'^[A-Za-z]:\\', path)) or '\\' in path
def to_posix(path: str | Path) ‑> str | pathlib.Path

Convert a Windows path to a POSIX path

Examples

>>> import wslPath
>>> pathwin = "hoge\fuga"
>>> wslPath.to_posix(pathwin)
hoge/fuga
>>> pathwin = "C:\hoge\fuga"
>>> wslPath.to_posix(pathwin)
/mnt/c/hoge/fuga
Expand source code
def to_posix(path: str | Path) -> str | Path:
    """Convert a Windows path to a POSIX path
    Examples:
        >>> import wslPath
        >>> pathwin = "hoge\\fuga"
        >>> wslPath.to_posix(pathwin)
        hoge/fuga

        >>> pathwin = "C:\\hoge\\fuga"
        >>> wslPath.to_posix(pathwin)
        /mnt/c/hoge/fuga
    """
    flag_path = isinstance(path, Path)
    path = str(path)
    if not is_windows_path(path):
        raise ValueError(f"{path} is an invalid Windows path")

    # Remove consecutive backslashes
    path = re.sub(r"\\\\+", r"\\", path)
    path = path.replace("\\", "/")

    # Convert drive letter to POSIX format
    drive_pattern = re.compile(r"^([A-Z]):/")
    if drive_pattern.search(path):
        drive, directory = path.split(":/", 1)
        drive = drive.lower()
        path = f"/mnt/{drive}/{directory}"

    if flag_path:
        path = Path(path)

    return path
def to_windows(path: str | Path) ‑> str | pathlib.Path

Convert a POSIX path to a Windows path Examples:

>>> import wslPath
>>> pathposix = "hoge/fuga"
>>> wslPath.to_windows(pathposix)
hoge\fuga
>>> pathposix = "/mnt/c/hoge/fuga"
>>> wslPath.to_windows(pathposix)
C:\hoge\fuga
Expand source code
def to_windows(path: str | Path) -> str | Path:
    """Convert a POSIX path to a Windows path
    Examples:
    >>> import wslPath
    >>> pathposix = "hoge/fuga"
    >>> wslPath.to_windows(pathposix)
    hoge\\fuga

    >>> pathposix = "/mnt/c/hoge/fuga"
    >>> wslPath.to_windows(pathposix)
    C:\\hoge\\fuga
    """
    flag_path = isinstance(path, Path)

    if has_invalid_windows_path_chars(path):
        raise ValueError(f"{path} includes invalid filepath characters on Windows")


    if not is_posix_path(path) and not isinstance(path, WindowsPath):
        raise ValueError(f"{path} is not a POSIX path")

    # Normalize slashes
    path = str(path).replace("\\", "/")
    path = re.sub(r"/+", "/", path)

    # Convert /mnt/c/ style paths to C:\
    if path.startswith("/mnt/"):
        drive_letter = path[5].upper()
        path = drive_letter + ":" + path[6:]

    path = path.replace("/", "\\")

    if flag_path:
        path = Path(path)

    return path