or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# uritemplate

1

2

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.

3

4

## Package Information

5

6

- **Package Name**: uritemplate

7

- **Language**: Python

8

- **Installation**: `pip install uritemplate`

9

10

## Core Imports

11

12

```python

13

from uritemplate import URITemplate, expand, partial, variables

14

```

15

16

Alternative imports for specific functionality:

17

18

```python

19

from uritemplate import URITemplate # Class-based approach

20

from uritemplate import expand # Direct expansion function

21

from uritemplate import partial # Partial expansion function

22

from uritemplate import variables # Variable extraction function

23

```

24

25

Internal types and classes (for advanced usage):

26

27

```python

28

from uritemplate.orderedset import OrderedSet

29

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

30

```

31

32

## Basic Usage

33

34

```python

35

from uritemplate import URITemplate, expand

36

37

# Basic template expansion using the URITemplate class

38

template = URITemplate('https://api.github.com/users/{username}/repos')

39

uri = template.expand(username='octocat')

40

print(uri) # https://api.github.com/users/octocat/repos

41

42

# Direct expansion using the expand function

43

uri = expand('https://api.github.com/users/{username}/repos', username='octocat')

44

print(uri) # https://api.github.com/users/octocat/repos

45

46

# Multiple variables with different expansion operators

47

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

48

uri = api_template.expand(endpoint='repos', page=2, per_page=50)

49

print(uri) # https://api.github.com/repos?page=2&per_page=50

50

51

# Using dictionary for variable values

52

variables_dict = {'username': 'octocat', 'repo': 'Hello-World'}

53

repo_template = URITemplate('https://api.github.com/repos/{username}/{repo}')

54

uri = repo_template.expand(variables_dict)

55

print(uri) # https://api.github.com/repos/octocat/Hello-World

56

```

57

58

## Architecture

59

60

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

61

62

- **Functional Interface**: Direct functions (`expand`, `partial`, `variables`) for immediate operations

63

- **Class-based Interface**: `URITemplate` class for reusable template objects with parsing optimization

64

65

Core components:

66

- **URITemplate**: Main template class that parses and expands URI templates

67

- **URIVariable**: Internal variable representation supporting all RFC 6570 operators

68

- **OrderedSet**: Custom ordered set implementation for maintaining variable name order

69

- **Operator**: Enum defining URI template expansion operators (simple, reserved, fragment, etc.)

70

71

## Capabilities

72

73

### Template Expansion

74

75

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

76

77

```python { .api }

78

def expand(

79

uri: str,

80

var_dict: Optional[VariableValueDict] = None,

81

**kwargs: VariableValue

82

) -> str:

83

"""

84

Expand the URI template with the given parameters.

85

86

Parameters:

87

- uri: The templated URI to expand

88

- var_dict: Optional dictionary with variables and values

89

- **kwargs: Alternative way to pass arguments

90

91

Returns:

92

Expanded URI string

93

"""

94

```

95

96

```python { .api }

97

class URITemplate:

98

def __init__(self, uri: str):

99

"""

100

Initialize a URI template.

101

102

Parameters:

103

- uri: The URI template string

104

"""

105

106

def expand(

107

self,

108

var_dict: Optional[VariableValueDict] = None,

109

**kwargs: VariableValue

110

) -> str:

111

"""

112

Expand the template with the given parameters.

113

114

Parameters:

115

- var_dict: Optional dictionary with variables and values

116

- **kwargs: Alternative way to pass arguments

117

118

Returns:

119

Expanded URI string

120

"""

121

```

122

123

### Partial Template Expansion

124

125

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

126

127

```python { .api }

128

def partial(

129

uri: str,

130

var_dict: Optional[VariableValueDict] = None,

131

**kwargs: VariableValue

132

) -> URITemplate:

133

"""

134

Partially expand the template with the given parameters.

135

136

If all parameters for the template are not given, return a

137

partially expanded template.

138

139

Parameters:

140

- uri: The templated URI to expand

141

- var_dict: Optional dictionary with variables and values

142

- **kwargs: Alternative way to pass arguments

143

144

Returns:

145

URITemplate instance with partially expanded template

146

"""

147

```

148

149

```python { .api }

150

class URITemplate:

151

def partial(

152

self,

153

var_dict: Optional[VariableValueDict] = None,

154

**kwargs: VariableValue

155

) -> URITemplate:

156

"""

157

Partially expand the template with the given parameters.

158

159

Parameters:

160

- var_dict: Optional dictionary with variables and values

161

- **kwargs: Alternative way to pass arguments

162

163

Returns:

164

URITemplate instance with partially expanded template

165

"""

166

```

167

168

#### Usage Example

169

170

```python

171

from uritemplate import partial, URITemplate

172

173

# Partial expansion with function

174

template_str = 'https://api.github.com/repos/{owner}/{repo}{/path}{?page,per_page}'

175

partial_template = partial(template_str, owner='octocat', repo='Hello-World')

176

print(str(partial_template)) # https://api.github.com/repos/octocat/Hello-World{/path}{?page,per_page}

177

178

# Complete the expansion later

179

final_uri = partial_template.expand(path='issues', page=1)

180

print(final_uri) # https://api.github.com/repos/octocat/Hello-World/issues?page=1

181

182

# Partial expansion with class

183

template = URITemplate('https://api.example.com{/version}/users{/user_id}{?fields}')

184

partial_result = template.partial(version='v1')

185

final_uri = partial_result.expand(user_id=123, fields='name,email')

186

print(final_uri) # https://api.example.com/v1/users/123?fields=name,email

187

```

188

189

### Variable Extraction

190

191

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

192

193

```python { .api }

194

def variables(uri: str) -> OrderedSet:

195

"""

196

Parse the variables of the template.

197

198

This returns all of the variable names in the URI Template.

199

200

Parameters:

201

- uri: The URI template string

202

203

Returns:

204

OrderedSet of variable names found in the template

205

"""

206

```

207

208

#### Usage Example

209

210

```python

211

from uritemplate import variables

212

213

# Extract variables from template

214

template_str = 'https://api.github.com/repos/{owner}/{repo}/issues{/number}{?state,labels}'

215

vars_found = variables(template_str)

216

print(list(vars_found)) # ['owner', 'repo', 'number', 'state', 'labels']

217

218

# Check if specific variables are present

219

if 'owner' in vars_found and 'repo' in vars_found:

220

print("Template requires owner and repo parameters")

221

222

# Get variable count

223

print(f"Template contains {len(vars_found)} variables")

224

```

225

226

### URI Template Class Properties

227

228

Access template properties and metadata through the URITemplate class.

229

230

```python { .api }

231

class URITemplate:

232

@property

233

def uri(self) -> str:

234

"""The original URI template string."""

235

236

@property

237

def variables(self) -> List[URIVariable]:

238

"""List of URIVariable objects representing parsed variables."""

239

240

@property

241

def variable_names(self) -> OrderedSet:

242

"""Set of variable names in the URI template."""

243

```

244

245

#### Usage Example

246

247

```python

248

from uritemplate import URITemplate

249

250

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

251

252

# Access original template string

253

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

254

255

# Get variable names

256

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

257

258

# Template comparison and hashing

259

template1 = URITemplate('https://api.example.com/{id}')

260

template2 = URITemplate('https://api.example.com/{id}')

261

print(template1 == template2) # True

262

263

# Templates can be used as dictionary keys

264

template_cache = {template1: "cached_result"}

265

```

266

267

### Internal Components (Advanced Usage)

268

269

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

270

271

```python { .api }

272

class URIVariable:

273

def __init__(self, var: str):

274

"""

275

Initialize a URI variable from a template expression.

276

277

Parameters:

278

- var: The variable expression string (e.g., "var", "+var", "?var,x,y")

279

"""

280

281

def expand(self, var_dict: Optional[VariableValueDict] = None) -> Mapping[str, str]:

282

"""

283

Expand this variable using the provided variable dictionary.

284

285

Parameters:

286

- var_dict: Dictionary of variable names to values

287

288

Returns:

289

Dictionary mapping the original variable expression to its expanded form

290

"""

291

292

# Properties

293

original: str # The original variable expression

294

operator: Operator # The expansion operator used

295

variables: List[Tuple[str, Dict[str, Any]]] # Variable names and their options

296

variable_names: List[str] # List of variable names in this expression

297

defaults: Dict[str, str] # Default values for variables

298

```

299

300

#### Usage Example

301

302

```python

303

from uritemplate.variable import URIVariable

304

305

# Parse a complex variable expression

306

var = URIVariable("?var,hello,x,y")

307

print(var.variable_names) # ['var', 'hello', 'x', 'y']

308

print(var.operator) # Operator.form_style_query

309

310

# Expand the variable

311

expansion = var.expand({

312

'var': 'value',

313

'hello': 'Hello World!',

314

'x': '1024',

315

'y': '768'

316

})

317

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

318

```

319

320

## Types

321

322

### Main API Types

323

324

```python { .api }

325

class URITemplate:

326

def __init__(self, uri: str): ...

327

def expand(

328

self,

329

var_dict: Optional[VariableValueDict] = None,

330

**kwargs: VariableValue

331

) -> str: ...

332

def partial(

333

self,

334

var_dict: Optional[VariableValueDict] = None,

335

**kwargs: VariableValue

336

) -> URITemplate: ...

337

338

# Properties

339

uri: str # The original URI template string

340

variables: List[URIVariable] # List of parsed variable objects

341

variable_names: OrderedSet # Set of variable names in the template

342

343

# Standard methods

344

def __str__(self) -> str: ...

345

def __repr__(self) -> str: ...

346

def __eq__(self, other: object) -> bool: ...

347

def __hash__(self) -> int: ...

348

349

def expand(

350

uri: str,

351

var_dict: Optional[VariableValueDict] = None,

352

**kwargs: VariableValue

353

) -> str: ...

354

355

def partial(

356

uri: str,

357

var_dict: Optional[VariableValueDict] = None,

358

**kwargs: VariableValue

359

) -> URITemplate: ...

360

361

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

362

```

363

364

### Supporting Types

365

366

```python { .api }

367

class OrderedSet:

368

def __init__(self, iterable: Optional[Iterable[str]] = None): ...

369

def add(self, key: str) -> None: ...

370

def discard(self, key: str) -> None: ...

371

def pop(self, last: bool = True) -> str: ...

372

def __len__(self) -> int: ...

373

def __contains__(self, key: object) -> bool: ...

374

def __iter__(self) -> Generator[str, None, None]: ...

375

def __reversed__(self) -> Generator[str, None, None]: ...

376

377

class URIVariable:

378

def __init__(self, var: str): ...

379

def expand(self, var_dict: Optional[VariableValueDict] = None) -> Mapping[str, str]: ...

380

381

# Properties

382

original: str # The original variable expression

383

operator: Operator # The expansion operator

384

variables: List[Tuple[str, Dict[str, Any]]] # Variable names and options

385

variable_names: List[str] # List of variable names

386

defaults: Dict[str, str] # Default values for variables

387

388

class Operator(Enum):

389

"""RFC 6570 URI Template expansion operators."""

390

default = "" # Simple string expansion: {var}

391

reserved = "+" # Reserved expansion: {+var}

392

fragment = "#" # Fragment expansion: {#var}

393

label_with_dot_prefix = "." # Label expansion: {.var}

394

path_segment = "/" # Path segment expansion: {/var}

395

path_style_parameter = ";" # Path-style parameter expansion: {;var}

396

form_style_query = "?" # Form-style query expansion: {?var}

397

form_style_query_continuation = "&" # Form-style query continuation: {&var}

398

399

# Type aliases for variable values

400

ScalarVariableValue = Union[int, float, complex, str, None]

401

VariableValue = Union[

402

Sequence[ScalarVariableValue],

403

List[ScalarVariableValue],

404

Mapping[str, ScalarVariableValue],

405

Tuple[str, ScalarVariableValue],

406

ScalarVariableValue

407

]

408

VariableValueDict = Dict[str, VariableValue]

409

```

410

411

## Advanced Usage Patterns

412

413

### Complex Variable Types

414

415

```python

416

from uritemplate import URITemplate

417

418

# List variables for path segments

419

template = URITemplate('https://api.example.com/{path*}')

420

uri = template.expand(path=['users', 'profile', 'settings'])

421

print(uri) # https://api.example.com/users/profile/settings

422

423

# Dictionary variables for query parameters

424

template = URITemplate('https://api.example.com/search{?params*}')

425

uri = template.expand(params={'q': 'python', 'sort': 'stars', 'order': 'desc'})

426

print(uri) # https://api.example.com/search?q=python&sort=stars&order=desc

427

428

# Mixed variable types

429

template = URITemplate('https://api.example.com/{+base}/search{?q,filters*}')

430

uri = template.expand(

431

base='https://search.example.com/api/v1',

432

q='machine learning',

433

filters={'category': 'tech', 'year': '2023'}

434

)

435

```

436

437

### Template Reuse and Performance

438

439

```python

440

from uritemplate import URITemplate

441

442

class GitHubAPI:

443

# Class-level template for reuse (parsed once)

444

repo_template = URITemplate('https://api.github.com/repos/{owner}/{repo}')

445

issues_template = URITemplate('https://api.github.com/repos/{owner}/{repo}/issues{/number}{?state,labels}')

446

447

def __init__(self, owner: str, repo: str):

448

self.owner = owner

449

self.repo = repo

450

451

def get_repo_url(self) -> str:

452

return self.repo_template.expand(owner=self.owner, repo=self.repo)

453

454

def get_issues_url(self, number: int = None, state: str = None) -> str:

455

params = {'owner': self.owner, 'repo': self.repo}

456

if number:

457

params['number'] = number

458

if state:

459

params['state'] = state

460

return self.issues_template.expand(params)

461

462

# Usage

463

api = GitHubAPI('octocat', 'Hello-World')

464

print(api.get_repo_url()) # https://api.github.com/repos/octocat/Hello-World

465

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

466

```

467

468

## Error Handling

469

470

The uritemplate package handles various edge cases gracefully:

471

472

- **Missing variables**: Unexpanded variables remain in template form during partial expansion

473

- **Invalid variable types**: Complex objects are converted to strings when possible

474

- **Empty values**: Empty strings and None values are handled according to RFC 6570 specification

475

- **Special characters**: Proper URL encoding is applied based on the expansion operator used

476

477

```python

478

from uritemplate import URITemplate, expand

479

480

# Missing variables in partial expansion

481

template = URITemplate('https://api.example.com/{service}/{version}{/endpoint}')

482

partial_result = template.partial(service='users')

483

print(str(partial_result)) # https://api.example.com/users/{version}{/endpoint}

484

485

# Empty and None values

486

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

487

print(uri) # https://api.example.com/

488

489

# Special character encoding

490

uri = expand('https://api.example.com/search{?q}', q='hello world & special chars!')

491

print(uri) # https://api.example.com/search?q=hello%20world%20%26%20special%20chars%21

492

```