CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-yarl

Yet another URL library - comprehensive URL parsing and manipulation for Python

Overview
Eval results
Files

path-operations.mddocs/

Path Operations

Path manipulation, normalization, and joining operations for URL path components, including filename and extension handling with support for complex path manipulations.

Capabilities

Path Construction and Joining

Methods for building and extending URL paths with proper encoding and normalization.

def joinpath(self, *other: str, encoded: bool = False) -> "URL":
    """
    Join URL path with additional path segments.
    
    Args:
        *other (str): Path segments to append
        encoded (bool): Whether path segments are already encoded
        
    Returns:
        URL: New URL with joined path segments
        
    Examples:
        url.joinpath('api', 'v1', 'users')
        url.joinpath('files', 'document.pdf')
        url.joinpath('path with spaces', encoded=False)
    """

def join(self, url: "URL") -> "URL":
    """
    Join this URL with another URL using RFC 3986 resolution rules.
    
    Args:
        url (URL): URL to resolve against this URL
        
    Returns:
        URL: New URL after RFC 3986 resolution
        
    Examples:
        base.join(URL('path/to/resource'))
        base.join(URL('../parent/resource'))
        base.join(URL('?query=value'))
    """

def __truediv__(self, name: str) -> "URL":
    """
    Append path segment using / operator.
    
    Args:
        name (str): Path segment to append
        
    Returns:
        URL: New URL with appended path segment
        
    Examples:
        url / 'api' / 'v1' / 'users'
        url / 'documents' / 'file.pdf'
    """

Path Component Access

Properties for accessing path components and segments.

@property
def raw_parts(self) -> tuple[str, ...]:
    """
    Raw path segments as tuple.
    
    Returns:
        tuple[str, ...]: Tuple of raw (encoded) path segments
        
    Examples:
        URL('/path/to/file').raw_parts  # ('/', 'path', 'to', 'file')
        URL('/api/v1/').raw_parts       # ('/', 'api', 'v1', '')
    """

@property
def parts(self) -> tuple[str, ...]:
    """
    Decoded path segments as tuple.
    
    Returns:
        tuple[str, ...]: Tuple of decoded path segments
    """

@property
def parent(self) -> "URL":
    """
    Parent URL (removes last path segment).
    
    Returns:
        URL: New URL with last path segment removed
        
    Examples:
        URL('/path/to/file').parent     # URL('/path/to')
        URL('/api/v1/users').parent     # URL('/api/v1')
        URL('/').parent                 # URL('/')
    """

@property
def raw_path(self) -> str:
    """Raw (encoded) path component"""

@property
def path(self) -> str:
    """Decoded path component"""

@property
def path_safe(self) -> str:
    """Path with safe decoding (preserves important characters like /)"""

Filename and Extension Operations

Methods and properties for working with filename components of paths.

@property
def raw_name(self) -> str:
    """
    Raw filename component (last path segment).
    
    Returns:
        str: Raw filename or empty string if path ends with /
    """

@property
def name(self) -> str:
    """
    Decoded filename component (last path segment).
    
    Returns:
        str: Decoded filename or empty string if path ends with /
        
    Examples:
        URL('/documents/report.pdf').name    # 'report.pdf'
        URL('/api/users/').name              # ''
        URL('/path/to/file').name            # 'file'
    """

@property
def raw_suffix(self) -> str:
    """
    Raw file extension including leading dot.
    
    Returns:
        str: Raw file extension or empty string if no extension
    """

@property
def suffix(self) -> str:
    """
    Decoded file extension including leading dot.
    
    Returns:
        str: Decoded file extension or empty string if no extension
        
    Examples:
        URL('/file.txt').suffix          # '.txt'
        URL('/archive.tar.gz').suffix    # '.gz'
        URL('/README').suffix            # ''
    """

@property
def raw_suffixes(self) -> tuple[str, ...]:
    """
    All raw file extensions as tuple.
    
    Returns:
        tuple[str, ...]: Tuple of all raw extensions
    """

@property
def suffixes(self) -> tuple[str, ...]:
    """
    All decoded file extensions as tuple.
    
    Returns:
        tuple[str, ...]: Tuple of all decoded extensions
        
    Examples:
        URL('/file.txt').suffixes           # ('.txt',)
        URL('/archive.tar.gz').suffixes     # ('.tar', '.gz')
        URL('/document.backup.old').suffixes # ('.backup', '.old')
    """

def with_name(self, name: str, *, encoded: bool = False) -> "URL":
    """
    Return URL with new filename component.
    
    Args:
        name (str): New filename to replace current filename
        encoded (bool): Whether name is already encoded
        
    Returns:
        URL: New URL with updated filename
        
    Raises:
        ValueError: If name contains path separators
        
    Examples:
        url.with_name('newfile.txt')
        url.with_name('document with spaces.pdf')
    """

def with_suffix(self, suffix: str, *, encoded: bool = False) -> "URL":
    """
    Return URL with new file extension.
    
    Args:
        suffix (str): New file extension (should include leading dot)
        encoded (bool): Whether suffix is already encoded
        
    Returns:
        URL: New URL with updated file extension
        
    Examples:
        url.with_suffix('.json')
        url.with_suffix('.backup.txt')
    """

Path Normalization

Built-in path normalization handles relative path components and ensures clean paths.

Path normalization automatically:

  • Resolves . (current directory) references
  • Resolves .. (parent directory) references
  • Removes duplicate slashes
  • Preserves trailing slashes when semantically significant

Usage Examples

Basic Path Operations

from yarl import URL

base_url = URL('https://example.com/api/v1')

# Append path segments
users_url = base_url.joinpath('users')
print(users_url)  # https://example.com/api/v1/users

user_url = base_url.joinpath('users', '123')
print(user_url)   # https://example.com/api/v1/users/123

# Multiple segments at once
deep_url = base_url.joinpath('resources', 'documents', 'files')
print(deep_url)   # https://example.com/api/v1/resources/documents/files

Using the / Operator

from yarl import URL

api_url = URL('https://api.example.com')

# Chain path segments
endpoint = api_url / 'v2' / 'users' / '456' / 'profile'
print(endpoint)  # https://api.example.com/v2/users/456/profile

# Mix with other operations
full_url = (api_url 
           / 'search' 
           / 'documents' 
           % {'q': 'python', 'limit': 10})
print(full_url)  # https://api.example.com/search/documents?q=python&limit=10

Working with Filenames

from yarl import URL

file_url = URL('https://cdn.example.com/documents/report.pdf')

# Access filename components
print(file_url.name)      # 'report.pdf'
print(file_url.suffix)    # '.pdf'
print(file_url.suffixes)  # ('.pdf',)

# Modify filename
new_file = file_url.with_name('summary.pdf')
print(new_file)  # https://cdn.example.com/documents/summary.pdf

# Change extension
txt_version = file_url.with_suffix('.txt')
print(txt_version)  # https://cdn.example.com/documents/report.txt

# Work with parent directories
parent = file_url.parent
print(parent)    # https://cdn.example.com/documents

grandparent = file_url.parent.parent  
print(grandparent)  # https://cdn.example.com

Complex File Extensions

from yarl import URL

archive_url = URL('https://example.com/files/backup.tar.gz')

print(archive_url.suffix)     # '.gz' (last extension)
print(archive_url.suffixes)   # ('.tar', '.gz') (all extensions)

# Change just the compression
uncompressed = archive_url.with_suffix('.tar')
print(uncompressed)  # https://example.com/files/backup.tar

# Multiple extensions
config_url = URL('https://example.com/config.local.dev.json')
print(config_url.suffixes)  # ('.local', '.dev', '.json')

# Remove all extensions by changing name
base_name = config_url.name.split('.')[0]  # 'config'
clean_url = config_url.with_name(base_name)
print(clean_url)  # https://example.com/config

Path Segments and Navigation

from yarl import URL

deep_url = URL('https://example.com/api/v1/users/123/documents/456')

# Access path segments  
print(deep_url.parts)  # ('/', 'api', 'v1', 'users', '123', 'documents', '456')

# Navigate up the hierarchy
print(deep_url.parent)                    # https://example.com/api/v1/users/123/documents
print(deep_url.parent.parent)             # https://example.com/api/v1/users/123
print(deep_url.parent.parent.parent)      # https://example.com/api/v1/users

# Build new paths from segments
segments = deep_url.parts[1:4]  # ('api', 'v1', 'users')
new_base = URL('https://example.com').joinpath(*segments)
print(new_base)  # https://example.com/api/v1/users

Path Normalization Examples

from yarl import URL

# Relative path resolution
messy_url = URL('https://example.com/api/../docs/./guide/../tutorial/basics.html')
print(messy_url)  # Automatically normalized to: https://example.com/docs/tutorial/basics.html

# Join with relative paths
base = URL('https://example.com/api/v1/users')
relative_join = base.join(URL('../docs/guide.html'))
print(relative_join)  # https://example.com/api/v1/docs/guide.html

# Complex relative navigation
complex_base = URL('https://example.com/app/module/submodule/')
back_and_forward = complex_base.join(URL('../../other/module/file.js'))
print(back_and_forward)  # https://example.com/app/other/module/file.js

URL Resolution (RFC 3986)

from yarl import URL

base_url = URL('https://example.com/app/current/page')

# Absolute URL resolution
absolute_result = base_url.join(URL('https://other.com/resource'))
print(absolute_result)  # https://other.com/resource

# Relative path resolution
relative_result = base_url.join(URL('other/resource'))
print(relative_result)  # https://example.com/app/current/other/resource

# Parent directory resolution
parent_result = base_url.join(URL('../sibling/resource'))
print(parent_result)  # https://example.com/app/sibling/resource

# Query-only resolution
query_result = base_url.join(URL('?query=value'))
print(query_result)  # https://example.com/app/current/page?query=value

# Fragment-only resolution  
fragment_result = base_url.join(URL('#section'))
print(fragment_result)  # https://example.com/app/current/page#section

Special Path Cases

from yarl import URL

# Root path operations
root_url = URL('https://example.com/')
api_from_root = root_url / 'api' / 'v1'
print(api_from_root)  # https://example.com/api/v1

# Empty path components
empty_url = URL('https://example.com')
with_empty = empty_url.joinpath('', 'api', '', 'users')
print(with_empty)  # https://example.com/api/users (empty segments ignored)

# Trailing slash preservation
trailing_url = URL('https://example.com/api/')
print(trailing_url.joinpath('users'))  # https://example.com/api/users
print(trailing_url / 'users')          # https://example.com/api/users

# Special characters in paths
special_url = URL('https://example.com').joinpath('files', 'my document.pdf')
print(special_url)  # https://example.com/files/my%20document.pdf (automatically encoded)

Install with Tessl CLI

npx tessl i tessl/pypi-yarl

docs

cache-management.md

core-url.md

index.md

path-operations.md

query-handling.md

url-modification.md

tile.json