or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Result

1

2

A Rust-inspired Result type for Python that enables robust error handling through explicit Ok/Err variants. The library provides type-safe value encapsulation with full type annotation support, allowing developers to replace traditional exception-based error handling with functional programming patterns.

3

4

## Package Information

5

6

- **Package Name**: result

7

- **Language**: Python

8

- **Installation**: `pip install result`

9

- **Python Requirements**: >=3.8

10

- **Type Support**: Full type annotations with `py.typed` marker

11

12

## Core Imports

13

14

```python

15

from result import Ok, Err, Result

16

```

17

18

For type checking and guards:

19

20

```python

21

from result import is_ok, is_err, OkErr

22

```

23

24

For functional utilities:

25

26

```python

27

from result import as_result, as_async_result, do, do_async

28

```

29

30

For exception handling:

31

32

```python

33

from result import UnwrapError

34

```

35

36

For version information:

37

38

```python

39

from result import __version__

40

print(__version__) # "0.17.0"

41

```

42

43

## Basic Usage

44

45

```python

46

from result import Ok, Err, Result, is_ok, is_err

47

48

def divide(a: int, b: int) -> Result[int, str]:

49

"""Divide two numbers, returning a Result type."""

50

if b == 0:

51

return Err("Cannot divide by zero")

52

return Ok(a // b)

53

54

# Using type guards for safe access

55

result = divide(10, 2)

56

if is_ok(result):

57

print(f"Success: {result.ok_value}") # Success: 5

58

elif is_err(result):

59

print(f"Error: {result.err_value}")

60

61

# Using isinstance for type checking

62

result = divide(10, 0)

63

if isinstance(result, Ok):

64

print(f"Success: {result.ok_value}")

65

elif isinstance(result, Err):

66

print(f"Error: {result.err_value}") # Error: Cannot divide by zero

67

68

# Python 3.10+ pattern matching

69

match divide(10, 3):

70

case Ok(value):

71

print(f"Result: {value}")

72

case Err(error):

73

print(f"Error: {error}")

74

```

75

76

## Architecture

77

78

The Result type implements a functional approach to error handling inspired by Rust's Result enum. Instead of relying on exceptions for control flow, it provides explicit success (`Ok`) and failure (`Err`) variants that must be handled consciously.

79

80

### Core Design Principles

81

82

- **Explicit Error Handling**: All potential failures are encoded in the type system, making error states visible and mandatory to handle

83

- **Type Safety**: Full generic type support ensures that both success values and error types are preserved through transformations

84

- **Immutability**: Result instances are immutable, preventing accidental state mutations

85

- **Composability**: Operations can be chained safely with short-circuiting behavior on errors

86

87

### Error Handling Philosophy

88

89

Traditional Python exception handling can lead to uncaught errors and unclear control flow:

90

91

```python

92

# Traditional approach - easy to miss error cases

93

def risky_operation():

94

if something_wrong():

95

raise ValueError("Something went wrong")

96

return success_value

97

98

try:

99

result = risky_operation()

100

# Easy to forget error handling

101

process(result)

102

except ValueError:

103

# Error handling often added as afterthought

104

handle_error()

105

```

106

107

The Result pattern makes error handling explicit and type-safe:

108

109

```python

110

# Result pattern - errors must be handled

111

def safe_operation() -> Result[SuccessType, ErrorType]:

112

if something_wrong():

113

return Err("Something went wrong")

114

return Ok(success_value)

115

116

result = safe_operation()

117

if is_ok(result):

118

process(result.ok_value) # Type-safe access

119

else:

120

handle_error(result.err_value) # Must handle error case

121

```

122

123

### Key Components

124

125

- **Result[T, E]**: Union type representing either success (`Ok[T]`) or failure (`Err[E]`)

126

- **Ok[T]**: Container for successful values with transformation methods

127

- **Err[E]**: Container for error values with recovery methods

128

- **Type Guards**: `is_ok()` and `is_err()` functions provide type-safe discrimination

129

- **Transformations**: `map()`, `and_then()`, `or_else()` enable safe operation chaining

130

- **Do Notation**: Generator-based syntax for complex operation sequences

131

132

This architecture enables building robust error-handling pipelines where failures are handled explicitly at each step, reducing bugs and improving code clarity.

133

134

## Capabilities

135

136

### Result Type Construction

137

138

Create Ok and Err instances to represent success and failure states.

139

140

```python { .api }

141

class Ok[T]:

142

def __init__(self, value: T) -> None:

143

"""Create an Ok instance containing a success value."""

144

145

class Err[E]:

146

def __init__(self, value: E) -> None:

147

"""Create an Err instance containing an error value."""

148

```

149

150

### Type Checking and Guards

151

152

Check Result types safely with type guards or isinstance.

153

154

```python { .api }

155

def is_ok(result: Result[T, E]) -> TypeGuard[Ok[T]]:

156

"""Type guard to check if a result is an Ok."""

157

158

def is_err(result: Result[T, E]) -> TypeGuard[Err[E]]:

159

"""Type guard to check if a result is an Err."""

160

```

161

162

Usage examples:

163

164

```python

165

result = Ok("success")

166

167

# Using type guard functions (recommended for type safety)

168

if is_ok(result):

169

# result is now typed as Ok[str]

170

value = result.ok_value

171

elif is_err(result):

172

# result is now typed as Err[E]

173

error = result.err_value

174

175

# Using isinstance checks

176

if isinstance(result, Ok):

177

value = result.ok_value

178

elif isinstance(result, Err):

179

error = result.err_value

180

181

# Using the OkErr convenience type

182

if isinstance(result, OkErr):

183

# result is either Ok or Err, but we don't know which

184

pass

185

```

186

187

### State Inspection Methods

188

189

Check the state of Result instances without type narrowing.

190

191

```python { .api }

192

# Ok methods

193

def is_ok(self) -> Literal[True]:

194

"""Return True for Ok instances."""

195

196

def is_err(self) -> Literal[False]:

197

"""Return False for Ok instances."""

198

199

# Err methods

200

def is_ok(self) -> Literal[False]:

201

"""Return False for Err instances."""

202

203

def is_err(self) -> Literal[True]:

204

"""Return True for Err instances."""

205

```

206

207

### Value Extraction

208

209

Extract success and error values from Result instances.

210

211

```python { .api }

212

# Ok value access

213

@property

214

def ok_value(self) -> T:

215

"""Access the success value (Ok only)."""

216

217

def ok(self) -> T:

218

"""Return the success value (Ok only)."""

219

220

def err(self) -> None:

221

"""Return None (Ok only)."""

222

223

# Err value access

224

@property

225

def err_value(self) -> E:

226

"""Access the error value (Err only)."""

227

228

def ok(self) -> None:

229

"""Return None (Err only)."""

230

231

def err(self) -> E:

232

"""Return the error value (Err only)."""

233

```

234

235

Usage examples:

236

237

```python

238

ok_result = Ok("success")

239

err_result = Err("failure")

240

241

# Direct property access (type-safe only after type checking)

242

if isinstance(ok_result, Ok):

243

value = ok_result.ok_value # "success"

244

245

if isinstance(err_result, Err):

246

error = err_result.err_value # "failure"

247

248

# Using ok() and err() methods

249

success_value = ok_result.ok() # "success"

250

error_value = err_result.err() # "failure"

251

```

252

253

### Object Protocol Methods

254

255

Standard Python object methods for comparison, hashing, and iteration.

256

257

```python { .api }

258

# Ok class methods

259

def __repr__(self) -> str:

260

"""Return string representation of Ok instance."""

261

262

def __eq__(self, other: Any) -> bool:

263

"""Check equality with another object."""

264

265

def __ne__(self, other: Any) -> bool:

266

"""Check inequality with another object."""

267

268

def __hash__(self) -> int:

269

"""Return hash value for Ok instance."""

270

271

def __iter__(self) -> Iterator[T]:

272

"""Allow iteration over Ok value (used in do notation)."""

273

274

# Err class methods

275

def __repr__(self) -> str:

276

"""Return string representation of Err instance."""

277

278

def __eq__(self, other: Any) -> bool:

279

"""Check equality with another object."""

280

281

def __ne__(self, other: Any) -> bool:

282

"""Check inequality with another object."""

283

284

def __hash__(self) -> int:

285

"""Return hash value for Err instance."""

286

287

def __iter__(self) -> Iterator[NoReturn]:

288

"""Special iterator that raises DoException (used in do notation)."""

289

```

290

291

Usage examples:

292

293

```python

294

ok1 = Ok("hello")

295

ok2 = Ok("hello")

296

ok3 = Ok("world")

297

298

print(repr(ok1)) # Ok('hello')

299

print(ok1 == ok2) # True

300

print(ok1 == ok3) # False

301

print(ok1 != ok3) # True

302

print(hash(ok1)) # Some hash value

303

304

err1 = Err("error")

305

err2 = Err("error")

306

print(repr(err1)) # Err('error')

307

print(err1 == err2) # True

308

309

# Iteration is used internally by do notation

310

for value in Ok("test"):

311

print(value) # "test"

312

```

313

314

### Deprecated Properties

315

316

Legacy properties maintained for backward compatibility.

317

318

```python { .api }

319

# Ok class

320

@property

321

def value(self) -> T:

322

"""

323

Return the inner value.

324

325

Warning:

326

Deprecated. Use `ok_value` or `err_value` instead.

327

This property will be removed in a future version.

328

"""

329

330

# Err class

331

@property

332

def value(self) -> E:

333

"""

334

Return the inner value.

335

336

Warning:

337

Deprecated. Use `ok_value` or `err_value` instead.

338

This property will be removed in a future version.

339

"""

340

```

341

342

Usage (not recommended):

343

344

```python

345

import warnings

346

347

ok_result = Ok("success")

348

with warnings.catch_warnings():

349

warnings.simplefilter("ignore", DeprecationWarning)

350

value = ok_result.value # "success" (but will show deprecation warning)

351

```

352

353

### Unwrap Operations

354

355

Extract values with various unwrap strategies and error handling.

356

357

```python { .api }

358

def unwrap(self) -> T:

359

"""

360

Return the value if Ok, raise UnwrapError if Err.

361

362

Raises:

363

UnwrapError: If called on an Err instance.

364

"""

365

366

def unwrap_err(self) -> E:

367

"""

368

Return the error if Err, raise UnwrapError if Ok.

369

370

Raises:

371

UnwrapError: If called on an Ok instance.

372

"""

373

374

def expect(self, message: str) -> T:

375

"""

376

Return the value if Ok, raise UnwrapError with custom message if Err.

377

378

Args:

379

message: Custom error message for UnwrapError.

380

381

Raises:

382

UnwrapError: If called on an Err instance.

383

"""

384

385

def expect_err(self, message: str) -> E:

386

"""

387

Return the error if Err, raise UnwrapError with custom message if Ok.

388

389

Args:

390

message: Custom error message for UnwrapError.

391

392

Raises:

393

UnwrapError: If called on an Ok instance.

394

"""

395

396

def unwrap_or(self, default: U) -> T | U:

397

"""

398

Return the value if Ok, return default if Err.

399

400

Args:

401

default: Default value to return for Err instances.

402

"""

403

404

def unwrap_or_else(self, op: Callable[[E], T]) -> T:

405

"""

406

Return the value if Ok, apply function to error if Err.

407

408

Args:

409

op: Function to apply to error value for Err instances.

410

"""

411

412

def unwrap_or_raise(self, e: Type[TBE]) -> T:

413

"""

414

Return the value if Ok, raise custom exception with error if Err.

415

416

Args:

417

e: Exception class to raise with the error value.

418

419

Raises:

420

e: Custom exception with error value as message.

421

"""

422

```

423

424

Usage examples:

425

426

```python

427

ok_result = Ok("success")

428

err_result = Err("failure")

429

430

# Basic unwrap (raises UnwrapError on failure)

431

try:

432

value = ok_result.unwrap() # "success"

433

value = err_result.unwrap() # raises UnwrapError

434

except UnwrapError as e:

435

print(f"Unwrap failed: {e}")

436

437

# Unwrap with custom message

438

try:

439

value = err_result.expect("Expected success") # raises UnwrapError

440

except UnwrapError as e:

441

print(f"Custom message: {e}")

442

443

# Unwrap with default value

444

value = ok_result.unwrap_or("default") # "success"

445

value = err_result.unwrap_or("default") # "default"

446

447

# Unwrap with function fallback

448

value = err_result.unwrap_or_else(lambda e: f"Error: {e}") # "Error: failure"

449

450

# Unwrap or raise custom exception

451

try:

452

value = err_result.unwrap_or_raise(ValueError) # raises ValueError("failure")

453

except ValueError as e:

454

print(f"Custom exception: {e}")

455

```

456

457

### Transformation Operations

458

459

Transform values and errors using map operations.

460

461

```python { .api }

462

def map(self, op: Callable[[T], U]) -> Result[U, E]:

463

"""

464

Transform the value if Ok, pass through if Err.

465

466

Args:

467

op: Function to transform the success value.

468

469

Returns:

470

Ok(op(value)) if Ok, unchanged Err if Err.

471

"""

472

473

async def map_async(self, op: Callable[[T], Awaitable[U]]) -> Result[U, E]:

474

"""

475

Async transform the value if Ok, pass through if Err.

476

477

Args:

478

op: Async function to transform the success value.

479

480

Returns:

481

Ok(await op(value)) if Ok, unchanged Err if Err.

482

"""

483

484

def map_or(self, default: U, op: Callable[[T], U]) -> U:

485

"""

486

Transform the value if Ok, return default if Err.

487

488

Args:

489

default: Default value to return for Err instances.

490

op: Function to transform the success value.

491

492

Returns:

493

op(value) if Ok, default if Err.

494

"""

495

496

def map_or_else(self, default_op: Callable[[], U], op: Callable[[T], U]) -> U:

497

"""

498

Transform the value if Ok, apply default function if Err.

499

500

Args:

501

default_op: Function to call for Err instances.

502

op: Function to transform the success value.

503

504

Returns:

505

op(value) if Ok, default_op() if Err.

506

"""

507

508

def map_err(self, op: Callable[[E], F]) -> Result[T, F]:

509

"""

510

Transform the error if Err, pass through if Ok.

511

512

Args:

513

op: Function to transform the error value.

514

515

Returns:

516

Unchanged Ok if Ok, Err(op(error)) if Err.

517

"""

518

```

519

520

Usage examples:

521

522

```python

523

ok_result = Ok(5)

524

err_result = Err("not a number")

525

526

# Transform success values

527

doubled = ok_result.map(lambda x: x * 2) # Ok(10)

528

failed = err_result.map(lambda x: x * 2) # Err("not a number")

529

530

# Transform with default value

531

result1 = ok_result.map_or(0, lambda x: x * 2) # 10

532

result2 = err_result.map_or(0, lambda x: x * 2) # 0

533

534

# Transform errors

535

better_err = err_result.map_err(lambda e: f"Error: {e}") # Err("Error: not a number")

536

```

537

538

### Chain Operations

539

540

Chain multiple Result-returning operations together.

541

542

```python { .api }

543

def and_then(self, op: Callable[[T], Result[U, E]]) -> Result[U, E]:

544

"""

545

Chain another Result-returning operation if Ok, pass through if Err.

546

547

Args:

548

op: Function that takes the success value and returns a Result.

549

550

Returns:

551

op(value) if Ok, unchanged Err if Err.

552

"""

553

554

async def and_then_async(self, op: Callable[[T], Awaitable[Result[U, E]]]) -> Result[U, E]:

555

"""

556

Async chain another Result-returning operation if Ok, pass through if Err.

557

558

Args:

559

op: Async function that takes the success value and returns a Result.

560

561

Returns:

562

await op(value) if Ok, unchanged Err if Err.

563

"""

564

565

def or_else(self, op: Callable[[E], Result[T, F]]) -> Result[T, F]:

566

"""

567

Chain alternative Result-returning operation if Err, pass through if Ok.

568

569

Args:

570

op: Function that takes the error value and returns a Result.

571

572

Returns:

573

Unchanged Ok if Ok, op(error) if Err.

574

"""

575

```

576

577

Usage examples:

578

579

```python

580

def parse_int(s: str) -> Result[int, str]:

581

try:

582

return Ok(int(s))

583

except ValueError:

584

return Err(f"'{s}' is not a valid integer")

585

586

def divide_by_two(n: int) -> Result[float, str]:

587

return Ok(n / 2.0)

588

589

# Chain operations

590

result = Ok("10").and_then(parse_int).and_then(divide_by_two) # Ok(5.0)

591

592

# Handle errors in chain

593

result = Err("failed").or_else(lambda e: Ok(f"Recovered from: {e}")) # Ok("Recovered from: failed")

594

```

595

596

### Inspection Operations

597

598

Inspect values without consuming the Result.

599

600

```python { .api }

601

def inspect(self, op: Callable[[T], Any]) -> Result[T, E]:

602

"""

603

Call function with the value if Ok, pass through unchanged.

604

605

Args:

606

op: Function to call with the success value (for side effects).

607

608

Returns:

609

The original Result unchanged.

610

"""

611

612

def inspect_err(self, op: Callable[[E], Any]) -> Result[T, E]:

613

"""

614

Call function with the error if Err, pass through unchanged.

615

616

Args:

617

op: Function to call with the error value (for side effects).

618

619

Returns:

620

The original Result unchanged.

621

"""

622

```

623

624

Usage examples:

625

626

```python

627

# Log success values without changing the Result

628

result = Ok("success").inspect(lambda x: print(f"Got value: {x}"))

629

# Prints: Got value: success

630

# result is still Ok("success")

631

632

# Log errors without changing the Result

633

result = Err("failed").inspect_err(lambda e: print(f"Error occurred: {e}"))

634

# Prints: Error occurred: failed

635

# result is still Err("failed")

636

```

637

638

### Function Decorators

639

640

Convert regular functions to return Result types.

641

642

```python { .api }

643

def as_result(*exceptions: Type[TBE]) -> Callable[[Callable[P, R]], Callable[P, Result[R, TBE]]]:

644

"""

645

Decorator to convert a function to return Result instead of raising exceptions.

646

647

Args:

648

*exceptions: Exception types to catch and convert to Err.

649

650

Returns:

651

Decorator function that wraps the original function.

652

653

Example:

654

@as_result(ValueError, TypeError)

655

def parse_int(s: str) -> int:

656

return int(s)

657

658

result = parse_int("123") # Ok(123)

659

result = parse_int("abc") # Err(ValueError(...))

660

"""

661

662

def as_async_result(*exceptions: Type[TBE]) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[Result[R, TBE]]]]:

663

"""

664

Decorator to convert an async function to return Result instead of raising exceptions.

665

666

Args:

667

*exceptions: Exception types to catch and convert to Err.

668

669

Returns:

670

Decorator function that wraps the original async function.

671

672

Example:

673

@as_async_result(ValueError, TypeError)

674

async def fetch_data(url: str) -> str:

675

# ... async code that might raise exceptions

676

return data

677

678

result = await fetch_data("http://example.com") # Ok(data) or Err(exception)

679

"""

680

```

681

682

Usage examples:

683

684

```python

685

@as_result(ValueError, TypeError)

686

def safe_int_conversion(value: str) -> int:

687

return int(value)

688

689

# Returns Ok(42) instead of int

690

result = safe_int_conversion("42")

691

692

# Returns Err(ValueError(...)) instead of raising

693

result = safe_int_conversion("not_a_number")

694

695

@as_async_result(ConnectionError, TimeoutError)

696

async def fetch_data(url: str) -> str:

697

# Some async operation that might fail

698

return "data"

699

700

# Usage

701

result = await fetch_data("http://example.com")

702

```

703

704

### Do Notation

705

706

Syntactic sugar for chaining Result operations using generator syntax.

707

708

```python { .api }

709

def do(gen: Generator[Result[T, E], None, None]) -> Result[T, E]:

710

"""

711

Do notation for Result - syntactic sugar for sequence of and_then() calls.

712

713

Args:

714

gen: Generator expression using Result values.

715

716

Returns:

717

The final Result from the generator.

718

719

Note:

720

Type annotation on the result is recommended for proper type inference.

721

"""

722

723

async def do_async(gen: Union[Generator[Result[T, E], None, None], AsyncGenerator[Result[T, E], None]]) -> Result[T, E]:

724

"""

725

Async version of do notation supporting both sync and async generators.

726

727

Args:

728

gen: Generator or async generator expression using Result values.

729

730

Returns:

731

The final Result from the generator.

732

"""

733

```

734

735

Usage examples:

736

737

```python

738

# Basic do notation

739

result: Result[int, str] = do(

740

Ok(x + y + z)

741

for x in Ok(1)

742

for y in Ok(2)

743

for z in Ok(3)

744

) # Ok(6)

745

746

# With error propagation - stops at first Err

747

result: Result[int, str] = do(

748

Ok(x + y)

749

for x in Ok(1)

750

for y in Err("failed") # This error propagates

751

) # Err("failed")

752

753

# Access previous values in later iterations

754

result: Result[str, str] = do(

755

Ok(f"{x}-{y}-{z}")

756

for x in Ok("a")

757

for y in Ok(f"{x}b") # Can use x from previous line

758

for z in Ok(f"{y}c") # Can use both x and y

759

) # Ok("a-ab-abc")

760

761

# Async do notation

762

async def get_async_result(x: int) -> Result[int, str]:

763

return Ok(x * 2)

764

765

result: Result[int, str] = await do_async(

766

Ok(x + y)

767

for x in await get_async_result(5) # Ok(10)

768

for y in Ok(3)

769

) # Ok(13)

770

```

771

772

### Exception Handling

773

774

Handle unwrap failures with custom exception types.

775

776

```python { .api }

777

class UnwrapError(Exception):

778

"""

779

Exception raised from unwrap and expect calls.

780

781

The original Result can be accessed via the .result attribute.

782

"""

783

784

def __init__(self, result: Result[object, object], message: str) -> None:

785

"""

786

Initialize UnwrapError with the original result and message.

787

788

Args:

789

result: The original Result that failed to unwrap.

790

message: Error message describing the failure.

791

"""

792

793

@property

794

def result(self) -> Result[Any, Any]:

795

"""Returns the original result that caused the unwrap failure."""

796

```

797

798

Usage examples:

799

800

```python

801

try:

802

value = Err("failed").unwrap()

803

except UnwrapError as e:

804

print(f"Unwrap failed: {e}")

805

original_result = e.result # Access the original Err("failed")

806

```

807

808

## Types

809

810

```python { .api }

811

# Type alias for Result

812

Result[T, E] = Union[Ok[T], Err[E]]

813

814

# Convenience constant for isinstance checks

815

OkErr: Final = (Ok, Err)

816

817

# Type variables

818

T = TypeVar("T", covariant=True) # Success type

819

E = TypeVar("E", covariant=True) # Error type

820

U = TypeVar("U") # Generic type variable

821

F = TypeVar("F") # Generic type variable

822

P = ParamSpec("P") # Function parameters

823

R = TypeVar("R") # Return type

824

TBE = TypeVar("TBE", bound=BaseException) # Exception type

825

826

# Package version

827

__version__: str = "0.17.0" # Package version string

828

```

829

830

## Pattern Matching (Python 3.10+)

831

832

The Result types support pattern matching with `__match_args__`:

833

834

```python

835

from result import Ok, Err

836

837

def handle_result(r: Result[int, str]) -> str:

838

match r:

839

case Ok(value):

840

return f"Success: {value}"

841

case Err(error):

842

return f"Error: {error}"

843

844

# Usage

845

print(handle_result(Ok(42))) # "Success: 42"

846

print(handle_result(Err("oops"))) # "Error: oops"

847

```

848

849

## Error Handling Best Practices

850

851

1. **Use type guards for safe access**: Always use `is_ok()`, `is_err()`, or `isinstance()` before accessing values.

852

853

2. **Prefer `unwrap_or()` over `unwrap()`**: Provide default values rather than risking exceptions.

854

855

3. **Chain operations with `and_then()`**: Build error-handling pipelines that short-circuit on failure.

856

857

4. **Use do notation for complex chains**: Simplify multiple sequential operations.

858

859

5. **Convert exceptions with decorators**: Use `@as_result()` to convert existing functions.

860

861

```python

862

# Good: Safe value access

863

if is_ok(result):

864

process_value(result.ok_value)

865

866

# Good: Default value handling

867

value = result.unwrap_or("default")

868

869

# Good: Operation chaining

870

final_result = (

871

initial_value

872

.and_then(validate)

873

.and_then(transform)

874

.map(format_output)

875

)

876

```