or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

django-integration.mdindex.mdspecification-matching.mdversion-operations.md

specification-matching.mddocs/

0

# Specification Matching

1

2

Flexible version requirement specifications for filtering and selecting versions based on ranges. Supports both simple syntax and NPM-style range specifications for comprehensive version matching capabilities.

3

4

## Capabilities

5

6

### Simple Specification Syntax

7

8

The SimpleSpec class provides an intuitive syntax for version requirements using standard comparison operators.

9

10

```python { .api }

11

class SimpleSpec:

12

def __init__(self, expression: str):

13

"""

14

Create a specification from a simple expression.

15

16

Args:

17

expression: Specification string using operators like '>=1.0.0,<2.0.0'

18

19

Supported operators:

20

- '==': Exact match

21

- '!=': Not equal

22

- '<': Less than

23

- '<=': Less than or equal

24

- '>': Greater than

25

- '>=': Greater than or equal

26

- Multiple requirements can be combined with commas

27

"""

28

```

29

30

**Syntax Examples:**

31

32

```python

33

# Single requirements

34

spec1 = SimpleSpec('>=1.0.0') # At least 1.0.0

35

spec2 = SimpleSpec('<2.0.0') # Less than 2.0.0

36

spec3 = SimpleSpec('==1.2.3') # Exactly 1.2.3

37

spec4 = SimpleSpec('!=1.0.0') # Not 1.0.0

38

39

# Combined requirements

40

spec5 = SimpleSpec('>=1.0.0,<2.0.0') # Between 1.0.0 and 2.0.0

41

spec6 = SimpleSpec('>=1.0.0,<2.0.0,!=1.5.0') # Range excluding 1.5.0

42

```

43

44

### NPM-Style Specifications

45

46

The NpmSpec class supports the complete NPM semver range specification syntax including advanced operators and ranges.

47

48

```python { .api }

49

class NpmSpec:

50

def __init__(self, expression: str):

51

"""

52

Create a specification from an NPM-style expression.

53

54

Args:

55

expression: NPM-style specification string

56

57

Supported syntax:

58

- '^1.0.0': Compatible within major version

59

- '~1.0.0': Compatible within minor version

60

- '1.0.0 - 1.9.0': Range from-to

61

- '1.x': Any minor/patch in major 1

62

- '>=1.0.0 <2.0.0': Combined requirements

63

- '>=1.0.0 || >=2.0.0': Alternative requirements (OR)

64

"""

65

```

66

67

**Syntax Examples:**

68

69

```python

70

# Caret ranges (compatible within major)

71

spec1 = NpmSpec('^1.0.0') # >=1.0.0 <2.0.0

72

73

# Tilde ranges (compatible within minor)

74

spec2 = NpmSpec('~1.2.0') # >=1.2.0 <1.3.0

75

76

# X-ranges

77

spec3 = NpmSpec('1.x') # >=1.0.0 <2.0.0

78

spec4 = NpmSpec('1.2.x') # >=1.2.0 <1.3.0

79

80

# Hyphen ranges

81

spec5 = NpmSpec('1.0.0 - 1.9.0') # >=1.0.0 <=1.9.0

82

83

# OR expressions

84

spec6 = NpmSpec('>=1.0.0 <1.5.0 || >=2.0.0') # Multiple ranges

85

```

86

87

### Version Matching

88

89

Test whether individual versions satisfy specification requirements.

90

91

```python { .api }

92

def match(self, version: Version) -> bool:

93

"""

94

Test if a version matches this specification.

95

96

Args:

97

version: Version object to test

98

99

Returns:

100

True if version satisfies specification

101

"""

102

103

def __contains__(self, version: Version) -> bool:

104

"""

105

Support 'version in spec' syntax.

106

107

Args:

108

version: Version object to test

109

110

Returns:

111

True if version satisfies specification

112

"""

113

```

114

115

**Usage Examples:**

116

117

```python

118

spec = SimpleSpec('>=1.0.0,<2.0.0')

119

120

# Using match method

121

print(spec.match(Version('1.5.0'))) # True

122

print(spec.match(Version('2.0.0'))) # False

123

124

# Using 'in' operator (recommended)

125

print(Version('1.5.0') in spec) # True

126

print(Version('0.9.0') in spec) # False

127

128

# NPM-style matching

129

npm_spec = NpmSpec('^1.0.0')

130

print(Version('1.2.3') in npm_spec) # True

131

print(Version('2.0.0') in npm_spec) # False

132

```

133

134

### Version Filtering

135

136

Filter collections of versions to find those matching specification requirements.

137

138

```python { .api }

139

def filter(self, versions: Iterable[Version]) -> Iterator[Version]:

140

"""

141

Filter versions that match this specification.

142

143

Args:

144

versions: Iterable of Version objects

145

146

Returns:

147

Iterator yielding matching versions

148

"""

149

```

150

151

**Usage Examples:**

152

153

```python

154

versions = [

155

Version('0.9.0'),

156

Version('1.0.0'),

157

Version('1.2.3'),

158

Version('1.5.0'),

159

Version('2.0.0'),

160

Version('2.1.0')

161

]

162

163

spec = SimpleSpec('>=1.0.0,<2.0.0')

164

matching = list(spec.filter(versions))

165

print([str(v) for v in matching]) # ['1.0.0', '1.2.3', '1.5.0']

166

167

# NPM-style filtering

168

npm_spec = NpmSpec('^1.0.0')

169

npm_matching = list(npm_spec.filter(versions))

170

print([str(v) for v in npm_matching]) # ['1.0.0', '1.2.3', '1.5.0']

171

```

172

173

### Best Version Selection

174

175

Select the highest version that matches specification requirements.

176

177

```python { .api }

178

def select(self, versions: Iterable[Version]) -> Version | None:

179

"""

180

Select the best (highest) version matching this specification.

181

182

Args:

183

versions: Iterable of Version objects

184

185

Returns:

186

Highest matching version, or None if no matches

187

"""

188

```

189

190

**Usage Examples:**

191

192

```python

193

versions = [

194

Version('1.0.0'),

195

Version('1.2.3'),

196

Version('1.5.0'),

197

Version('2.0.0')

198

]

199

200

spec = SimpleSpec('>=1.0.0,<2.0.0')

201

best = spec.select(versions)

202

print(best) # Version('1.5.0')

203

204

# No matches returns None

205

strict_spec = SimpleSpec('>=3.0.0')

206

no_match = strict_spec.select(versions)

207

print(no_match) # None

208

```

209

210

### Base Specification Class

211

212

The BaseSpec class provides the foundation for all specification types with common functionality.

213

214

```python { .api }

215

class BaseSpec:

216

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

217

218

@classmethod

219

def parse(cls, expression: str, syntax: str = 'simple'): ...

220

221

def filter(self, versions): ...

222

def match(self, version): ...

223

def select(self, versions): ...

224

def __contains__(self, version): ...

225

226

@classmethod

227

def register_syntax(cls, subclass): ... # For registering new syntax types

228

```

229

230

### Specification Parsing

231

232

Create specifications with explicit syntax control using the BaseSpec.parse method.

233

234

```python { .api }

235

@classmethod

236

def parse(cls, expression: str, syntax: str = 'simple') -> 'BaseSpec':

237

"""

238

Parse specification expression with explicit syntax.

239

240

Args:

241

expression: Specification string

242

syntax: 'simple' or 'npm'

243

244

Returns:

245

Appropriate specification object (SimpleSpec or NpmSpec)

246

"""

247

```

248

249

**Usage Examples:**

250

251

```python

252

# Parse with explicit syntax using BaseSpec

253

from semantic_version import BaseSpec

254

255

simple_spec = BaseSpec.parse('>=1.0.0,<2.0.0', syntax='simple')

256

npm_spec = BaseSpec.parse('^1.0.0', syntax='npm')

257

258

# Default syntax is 'simple'

259

default_spec = BaseSpec.parse('>=1.0.0')

260

261

# Direct class usage (recommended for known syntax)

262

simple_spec = SimpleSpec('>=1.0.0,<2.0.0')

263

npm_spec = NpmSpec('^1.0.0')

264

```

265

266

### Utility Function

267

268

Convenient function for quick version-specification matching.

269

270

```python { .api }

271

def match(spec: str, version: str) -> bool:

272

"""

273

Test if a version string matches a specification string.

274

275

Args:

276

spec: Specification string (uses simple syntax)

277

version: Version string to test

278

279

Returns:

280

True if version matches specification

281

"""

282

```

283

284

**Usage Examples:**

285

286

```python

287

# Quick matching without creating objects

288

print(match('>=1.0.0', '1.2.3')) # True

289

print(match('<2.0.0', '2.0.0')) # False

290

print(match('==1.0.0', '1.0.0+build')) # True (build ignored)

291

```

292

293

## Advanced Usage Patterns

294

295

### Prerelease Handling

296

297

Specifications have specific behavior with prerelease versions:

298

299

```python

300

spec = SimpleSpec('>=1.0.0')

301

302

# Prerelease versions don't satisfy non-prerelease requirements

303

print(Version('1.0.0-alpha') in spec) # False

304

305

# But explicit prerelease specs work

306

prerelease_spec = SimpleSpec('>=1.0.0-alpha')

307

print(Version('1.0.0-alpha') in prerelease_spec) # True

308

print(Version('1.0.0') in prerelease_spec) # True

309

```

310

311

### Build Metadata

312

313

Build metadata is ignored in version matching:

314

315

```python

316

spec = SimpleSpec('==1.0.0')

317

318

print(Version('1.0.0') in spec) # True

319

print(Version('1.0.0+build1') in spec) # True

320

print(Version('1.0.0+build2') in spec) # True

321

```

322

323

### Complex NPM Ranges

324

325

Advanced NPM specification patterns:

326

327

```python

328

# OR expressions for multiple acceptable ranges

329

multi_range = NpmSpec('>=1.0.0 <1.5.0 || >=2.0.0 <3.0.0')

330

print(Version('1.2.0') in multi_range) # True

331

print(Version('1.8.0') in multi_range) # False

332

print(Version('2.5.0') in multi_range) # True

333

334

# Partial version matching

335

partial_spec = NpmSpec('1.2') # Equivalent to >=1.2.0 <1.3.0

336

print(Version('1.2.0') in partial_spec) # True

337

print(Version('1.2.5') in partial_spec) # True

338

print(Version('1.3.0') in partial_spec) # False

339

```

340

341

## Internal Specification Architecture

342

343

Understanding the internal classes can help with advanced usage and debugging of complex version matching scenarios.

344

345

### Range Class

346

347

The Range class represents individual version constraints with specific operators and policies.

348

349

```python { .api }

350

class Range:

351

def __init__(self, operator, target, prerelease_policy='natural', build_policy='implicit'):

352

"""

353

Create a range constraint.

354

355

Args:

356

operator: '==', '!=', '<', '<=', '>', '>='

357

target: Version object to compare against

358

prerelease_policy: 'natural', 'always', 'same-patch'

359

build_policy: 'implicit', 'strict'

360

"""

361

362

def match(self, version): ...

363

```

364

365

### Prerelease and Build Policies

366

367

- **prerelease_policy='natural'**: Prerelease versions don't satisfy non-prerelease constraints

368

- **prerelease_policy='always'**: Prerelease versions can satisfy any constraint

369

- **prerelease_policy='same-patch'**: Prerelease versions only considered if target has same major.minor.patch

370

- **build_policy='implicit'**: Build metadata ignored in comparisons (default)

371

- **build_policy='strict'**: Build metadata must match exactly

372

373

### Clause Combinators

374

375

```python { .api }

376

class Always:

377

def match(self, version): ... # Always returns True

378

379

class Never:

380

def match(self, version): ... # Always returns False

381

382

class AllOf:

383

def __init__(self, *clauses): ... # AND combination

384

def match(self, version): ...

385

386

class AnyOf:

387

def __init__(self, *clauses): ... # OR combination

388

def match(self, version): ...

389

```

390

391

## Error Handling

392

393

Specification classes handle errors consistently:

394

395

```python

396

# Invalid specification syntax

397

try:

398

invalid_spec = SimpleSpec('invalid syntax')

399

except ValueError as e:

400

print(f"Invalid specification: {e}")

401

402

# Invalid NPM syntax

403

try:

404

invalid_npm = NpmSpec('^^1.0.0') # Double caret invalid

405

except ValueError as e:

406

print(f"Invalid NPM specification: {e}")

407

```

408

409

## Performance Considerations

410

411

- Specifications are compiled once and can be reused for multiple matches

412

- Use `filter()` for large collections rather than individual `match()` calls

413

- `select()` is optimized and stops at the first highest version found

414

- Consider caching specification objects for repeated use