or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-uritemplate

Implementation of RFC 6570 URI Templates for Python applications

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/uritemplate@4.2.x

To install, run

npx @tessl/cli install tessl/pypi-uritemplate@4.2.0

index.mddocs/

uritemplate

A Python implementation of RFC 6570 URI Templates that enables creation and expansion of URI templates according to the official specification. Provides both class-based and functional interfaces for creating dynamic URIs from templates and variable substitutions.

Package Information

  • Package Name: uritemplate
  • Language: Python
  • Installation: pip install uritemplate

Core Imports

from uritemplate import URITemplate, expand, partial, variables

Alternative imports for specific functionality:

from uritemplate import URITemplate  # Class-based approach
from uritemplate import expand        # Direct expansion function
from uritemplate import partial       # Partial expansion function
from uritemplate import variables     # Variable extraction function

Internal types and classes (for advanced usage):

from uritemplate.orderedset import OrderedSet
from uritemplate.variable import URIVariable, VariableValue, VariableValueDict, ScalarVariableValue

Basic Usage

from uritemplate import URITemplate, expand

# Basic template expansion using the URITemplate class
template = URITemplate('https://api.github.com/users/{username}/repos')
uri = template.expand(username='octocat')
print(uri)  # https://api.github.com/users/octocat/repos

# Direct expansion using the expand function
uri = expand('https://api.github.com/users/{username}/repos', username='octocat')
print(uri)  # https://api.github.com/users/octocat/repos

# Multiple variables with different expansion operators
api_template = URITemplate('https://api.github.com{/endpoint}{?page,per_page}')
uri = api_template.expand(endpoint='repos', page=2, per_page=50)
print(uri)  # https://api.github.com/repos?page=2&per_page=50

# Using dictionary for variable values  
variables_dict = {'username': 'octocat', 'repo': 'Hello-World'}
repo_template = URITemplate('https://api.github.com/repos/{username}/{repo}')
uri = repo_template.expand(variables_dict)
print(uri)  # https://api.github.com/repos/octocat/Hello-World

Architecture

The uritemplate package follows a simple, focused design with two main interfaces:

  • Functional Interface: Direct functions (expand, partial, variables) for immediate operations
  • Class-based Interface: URITemplate class for reusable template objects with parsing optimization

Core components:

  • URITemplate: Main template class that parses and expands URI templates
  • URIVariable: Internal variable representation supporting all RFC 6570 operators
  • OrderedSet: Custom ordered set implementation for maintaining variable name order
  • Operator: Enum defining URI template expansion operators (simple, reserved, fragment, etc.)

Capabilities

Template Expansion

Expand URI templates with variable substitutions using either the functional or class-based interface.

def expand(
    uri: str,
    var_dict: Optional[VariableValueDict] = None,
    **kwargs: VariableValue
) -> str:
    """
    Expand the URI template with the given parameters.
    
    Parameters:
    - uri: The templated URI to expand
    - var_dict: Optional dictionary with variables and values
    - **kwargs: Alternative way to pass arguments
    
    Returns:
    Expanded URI string
    """
class URITemplate:
    def __init__(self, uri: str):
        """
        Initialize a URI template.
        
        Parameters:
        - uri: The URI template string
        """
        
    def expand(
        self,
        var_dict: Optional[VariableValueDict] = None,
        **kwargs: VariableValue
    ) -> str:
        """
        Expand the template with the given parameters.
        
        Parameters:
        - var_dict: Optional dictionary with variables and values
        - **kwargs: Alternative way to pass arguments
        
        Returns:
        Expanded URI string
        """

Partial Template Expansion

Partially expand templates, leaving unresolved variables as template expressions for later expansion.

def partial(
    uri: str,
    var_dict: Optional[VariableValueDict] = None,
    **kwargs: VariableValue
) -> URITemplate:
    """
    Partially expand the template with the given parameters.
    
    If all parameters for the template are not given, return a
    partially expanded template.
    
    Parameters:
    - uri: The templated URI to expand
    - var_dict: Optional dictionary with variables and values
    - **kwargs: Alternative way to pass arguments
    
    Returns:
    URITemplate instance with partially expanded template
    """
class URITemplate:
    def partial(
        self,
        var_dict: Optional[VariableValueDict] = None,
        **kwargs: VariableValue
    ) -> URITemplate:
        """
        Partially expand the template with the given parameters.
        
        Parameters:
        - var_dict: Optional dictionary with variables and values
        - **kwargs: Alternative way to pass arguments
        
        Returns:
        URITemplate instance with partially expanded template
        """

Usage Example

from uritemplate import partial, URITemplate

# Partial expansion with function
template_str = 'https://api.github.com/repos/{owner}/{repo}{/path}{?page,per_page}'
partial_template = partial(template_str, owner='octocat', repo='Hello-World')
print(str(partial_template))  # https://api.github.com/repos/octocat/Hello-World{/path}{?page,per_page}

# Complete the expansion later
final_uri = partial_template.expand(path='issues', page=1)
print(final_uri)  # https://api.github.com/repos/octocat/Hello-World/issues?page=1

# Partial expansion with class
template = URITemplate('https://api.example.com{/version}/users{/user_id}{?fields}')
partial_result = template.partial(version='v1')
final_uri = partial_result.expand(user_id=123, fields='name,email')
print(final_uri)  # https://api.example.com/v1/users/123?fields=name,email

Variable Extraction

Extract all variable names from a URI template for introspection and validation.

def variables(uri: str) -> OrderedSet:
    """
    Parse the variables of the template.
    
    This returns all of the variable names in the URI Template.
    
    Parameters:
    - uri: The URI template string
    
    Returns:
    OrderedSet of variable names found in the template
    """

Usage Example

from uritemplate import variables

# Extract variables from template
template_str = 'https://api.github.com/repos/{owner}/{repo}/issues{/number}{?state,labels}'
vars_found = variables(template_str)
print(list(vars_found))  # ['owner', 'repo', 'number', 'state', 'labels']

# Check if specific variables are present
if 'owner' in vars_found and 'repo' in vars_found:
    print("Template requires owner and repo parameters")
    
# Get variable count
print(f"Template contains {len(vars_found)} variables")

URI Template Class Properties

Access template properties and metadata through the URITemplate class.

class URITemplate:
    @property
    def uri(self) -> str:
        """The original URI template string."""
        
    @property
    def variables(self) -> List[URIVariable]:
        """List of URIVariable objects representing parsed variables."""
        
    @property  
    def variable_names(self) -> OrderedSet:
        """Set of variable names in the URI template."""

Usage Example

from uritemplate import URITemplate

template = URITemplate('https://api.github.com/{endpoint}{?page,per_page}')

# Access original template string
print(template.uri)  # https://api.github.com/{endpoint}{?page,per_page}

# Get variable names
print(list(template.variable_names))  # ['endpoint', 'page', 'per_page']

# Template comparison and hashing
template1 = URITemplate('https://api.example.com/{id}')
template2 = URITemplate('https://api.example.com/{id}')
print(template1 == template2)  # True

# Templates can be used as dictionary keys
template_cache = {template1: "cached_result"}

Internal Components (Advanced Usage)

Access to lower-level components for advanced template manipulation and introspection.

class URIVariable:
    def __init__(self, var: str):
        """
        Initialize a URI variable from a template expression.
        
        Parameters:
        - var: The variable expression string (e.g., "var", "+var", "?var,x,y")
        """
        
    def expand(self, var_dict: Optional[VariableValueDict] = None) -> Mapping[str, str]:
        """
        Expand this variable using the provided variable dictionary.
        
        Parameters:
        - var_dict: Dictionary of variable names to values
        
        Returns:
        Dictionary mapping the original variable expression to its expanded form
        """
        
    # Properties
    original: str  # The original variable expression
    operator: Operator  # The expansion operator used
    variables: List[Tuple[str, Dict[str, Any]]]  # Variable names and their options
    variable_names: List[str]  # List of variable names in this expression
    defaults: Dict[str, str]  # Default values for variables

Usage Example

from uritemplate.variable import URIVariable

# Parse a complex variable expression
var = URIVariable("?var,hello,x,y")
print(var.variable_names)  # ['var', 'hello', 'x', 'y']
print(var.operator)  # Operator.form_style_query

# Expand the variable
expansion = var.expand({
    'var': 'value', 
    'hello': 'Hello World!',
    'x': '1024',
    'y': '768'
})
print(expansion)  # {'?var,hello,x,y': '?var=value&hello=Hello%20World%21&x=1024&y=768'}

Types

Main API Types

class URITemplate:
    def __init__(self, uri: str): ...
    def expand(
        self, 
        var_dict: Optional[VariableValueDict] = None, 
        **kwargs: VariableValue
    ) -> str: ...
    def partial(
        self, 
        var_dict: Optional[VariableValueDict] = None, 
        **kwargs: VariableValue
    ) -> URITemplate: ...
    
    # Properties
    uri: str  # The original URI template string
    variables: List[URIVariable]  # List of parsed variable objects
    variable_names: OrderedSet  # Set of variable names in the template
    
    # Standard methods
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...

def expand(
    uri: str,
    var_dict: Optional[VariableValueDict] = None,
    **kwargs: VariableValue
) -> str: ...

def partial(
    uri: str,
    var_dict: Optional[VariableValueDict] = None,
    **kwargs: VariableValue
) -> URITemplate: ...

def variables(uri: str) -> OrderedSet: ...

Supporting Types

class OrderedSet:
    def __init__(self, iterable: Optional[Iterable[str]] = None): ...
    def add(self, key: str) -> None: ...
    def discard(self, key: str) -> None: ...
    def pop(self, last: bool = True) -> str: ...
    def __len__(self) -> int: ...
    def __contains__(self, key: object) -> bool: ...
    def __iter__(self) -> Generator[str, None, None]: ...
    def __reversed__(self) -> Generator[str, None, None]: ...

class URIVariable:
    def __init__(self, var: str): ...
    def expand(self, var_dict: Optional[VariableValueDict] = None) -> Mapping[str, str]: ...
    
    # Properties
    original: str  # The original variable expression
    operator: Operator  # The expansion operator
    variables: List[Tuple[str, Dict[str, Any]]]  # Variable names and options
    variable_names: List[str]  # List of variable names
    defaults: Dict[str, str]  # Default values for variables

class Operator(Enum):
    """RFC 6570 URI Template expansion operators."""
    default = ""  # Simple string expansion: {var}
    reserved = "+"  # Reserved expansion: {+var}
    fragment = "#"  # Fragment expansion: {#var}
    label_with_dot_prefix = "."  # Label expansion: {.var}
    path_segment = "/"  # Path segment expansion: {/var}
    path_style_parameter = ";"  # Path-style parameter expansion: {;var}
    form_style_query = "?"  # Form-style query expansion: {?var}
    form_style_query_continuation = "&"  # Form-style query continuation: {&var}

# Type aliases for variable values
ScalarVariableValue = Union[int, float, complex, str, None]
VariableValue = Union[
    Sequence[ScalarVariableValue],
    List[ScalarVariableValue], 
    Mapping[str, ScalarVariableValue],
    Tuple[str, ScalarVariableValue],
    ScalarVariableValue
]
VariableValueDict = Dict[str, VariableValue]

Advanced Usage Patterns

Complex Variable Types

from uritemplate import URITemplate

# List variables for path segments
template = URITemplate('https://api.example.com/{path*}')
uri = template.expand(path=['users', 'profile', 'settings'])
print(uri)  # https://api.example.com/users/profile/settings

# Dictionary variables for query parameters
template = URITemplate('https://api.example.com/search{?params*}')
uri = template.expand(params={'q': 'python', 'sort': 'stars', 'order': 'desc'})
print(uri)  # https://api.example.com/search?q=python&sort=stars&order=desc

# Mixed variable types
template = URITemplate('https://api.example.com/{+base}/search{?q,filters*}')
uri = template.expand(
    base='https://search.example.com/api/v1',
    q='machine learning',
    filters={'category': 'tech', 'year': '2023'}
)

Template Reuse and Performance

from uritemplate import URITemplate

class GitHubAPI:
    # Class-level template for reuse (parsed once)
    repo_template = URITemplate('https://api.github.com/repos/{owner}/{repo}')
    issues_template = URITemplate('https://api.github.com/repos/{owner}/{repo}/issues{/number}{?state,labels}')
    
    def __init__(self, owner: str, repo: str):
        self.owner = owner
        self.repo = repo
    
    def get_repo_url(self) -> str:
        return self.repo_template.expand(owner=self.owner, repo=self.repo)
    
    def get_issues_url(self, number: int = None, state: str = None) -> str:
        params = {'owner': self.owner, 'repo': self.repo}
        if number:
            params['number'] = number
        if state:
            params['state'] = state
        return self.issues_template.expand(params)

# Usage
api = GitHubAPI('octocat', 'Hello-World')
print(api.get_repo_url())  # https://api.github.com/repos/octocat/Hello-World
print(api.get_issues_url(state='open'))  # https://api.github.com/repos/octocat/Hello-World/issues?state=open

Error Handling

The uritemplate package handles various edge cases gracefully:

  • Missing variables: Unexpanded variables remain in template form during partial expansion
  • Invalid variable types: Complex objects are converted to strings when possible
  • Empty values: Empty strings and None values are handled according to RFC 6570 specification
  • Special characters: Proper URL encoding is applied based on the expansion operator used
from uritemplate import URITemplate, expand

# Missing variables in partial expansion
template = URITemplate('https://api.example.com/{service}/{version}{/endpoint}')
partial_result = template.partial(service='users')
print(str(partial_result))  # https://api.example.com/users/{version}{/endpoint}

# Empty and None values
uri = expand('https://api.example.com{/path}{?query}', path='', query=None)
print(uri)  # https://api.example.com/

# Special character encoding
uri = expand('https://api.example.com/search{?q}', q='hello world & special chars!')
print(uri)  # https://api.example.com/search?q=hello%20world%20%26%20special%20chars%21