Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Accord

Accord brings the robust error handling and optional value patterns from Rust's Result and Option types to Python. This library provides a type-safe way to handle operations that can fail or may not have a value, leading to more predictable and maintainable code.

We intend not to use any kind of non-std library on Accord, so we do not need any extra dependency as a drawback for using it.

Why "Accord"?

The tale I weave for you now is about a puppet that travels the world.

The puppet's goal is to observe how humans live their lives.

This puppet continues its journey still, carrying its large suitcase with it...

Features

  • Result<T, E>: Represents either a success (Ok(T)) or a failure (Err(E)).
  • Option<T>: Represents an optional value, being either Some(T) or None.
  • Ergonomic API: Methods like map, and_then, or_else, unwrap, expect provide powerful ways to work with these types.
  • Type Safety: Leverages Python's type hinting for compile-time checks.
  • Sealed Types: Result and Option are sealed, preventing arbitrary subclassing and enforcing usage of provided variants (Ok/Err, Some/None).

Installation

[TBD]

Usage

Result

from accord.result import Result, Ok, Err

def divide(a: int, b: int) -> Result[int, str]:
    if b == 0:
        return Err("Division by zero is not allowed.")
    return Ok(a // b)

# Successful operation
result1 = divide(10, 2)
if result1.is_ok():
    print(f"Success: {result1.unwrap()}") # Output: Success: 5
else:
    print(f"Error: {result1.unwrap_err()}")

# Failed operation
result2 = divide(10, 0)
if result2.is_ok():
    print(f"Success: {result2.unwrap()}")
else:
    print(f"Error: {result2.unwrap_err()}") # Output: Error: Division by zero is not allowed.

# Using expect for cleaner unwrap with panic message
try:
    value = divide(10, 0).expect("Failed to divide numbers.")
except RuntimeError as e:
    print(e) # Output: Failed to divide numbers.: 'Division by zero is not allowed.'

# Chaining operations with and_then
def add_one_if_even(n: int) -> Result[int, str]:
    if n % 2 == 0:
        return Ok(n + 1)
    else:
        return Err("Number is odd")

divide(10, 2).and_then(add_one_if_even) # Ok(5) -> add_one_if_even(5) -> Err("Number is odd")
# Returns: Err('Number is odd')

divide(8, 2).and_then(add_one_if_even) # Ok(4) -> add_one_if_even(4) -> Ok(5)
# Returns: Ok(5)

Option

from accord.option import Option, Some, None

def find_user(user_id: int) -> Option[str]:
    if user_id == 1:
        return Some("Alice")
    return None

user1 = find_user(1)
if user1.is_some():
    print(f"User found: {user1.unwrap()}") # Output: User found: Alice
else:
    print("User not found.")

user2 = find_user(2)
print(f"User: {user2.unwrap_or('Guest')}") # Output: User: Guest

# Using expect
try:
    user_name = find_user(2).expect("User with ID 2 not found.")
except RuntimeError as e:
    print(e) # Output: User with ID 2 not found.

# Mapping over an Option
user_id_option: Option[int] = Some(123)
mapped_option = user_id_option.map(lambda x: f"User ID: {x}") # Some("User ID: 123")
None.map(lambda x: f"User ID: {x}") # None

# Chaining operations with and_then
def get_user_id_as_str(user_id: int) -> Option[str]:
    return Some(str(user_id))

Some(456).and_then(get_user_id_as_str) # Some(456) -> get_user_id_as_str(456) -> Some("456")
# Returns: Some("456")

None.and_then(get_user_id_as_str) # None -> Returns None
# Returns: None

FAQ

Is this README generated by AI?

Yes.

I was feeling lazy. I'll make it myself in the future.

What is Result and Option?

  • Result<T, E>: This type represents the outcome of an operation that might succeed or fail.

    • Ok(T): Indicates success and holds a value of type T.
    • Err(E): Indicates failure and holds an error value of type E.
    • It's Rust's primary way of handling recoverable errors without exceptions.
  • Option<T>: This type represents a value that might be present or absent.

    • Some(T): Indicates that a value of type T is present.
    • None: Indicates the absence of a value.
    • It's used for values that are optional, like the result of a search that might not find anything.

Why use Result and Option in Python?

Python traditionally uses exceptions for errors and None for optional values. However, Result and Option offer several benefits:

  • Explicit Error Handling: Result forces you to consider the error case at compile time (with type checkers) or runtime, making error handling more deliberate than relying on buried exceptions.
  • Clearer Intent: Option makes it explicit when a value might be missing, distinguishing it from other forms of "empty" or "null" that might arise from different contexts.
  • Functional Programming Patterns: These types are monadic, enabling elegant chaining of operations using methods like map and and_then, leading to more expressive and composable code.
  • Avoids None Ambiguity: In Python, None can sometimes be ambiguous. Option clearly separates the absence of a value from other potential "falsy" values.

How do Ok/Err and Some/None relate to Result/Option?

Result and Option are abstract base classes (or type aliases) that define the common interface. Ok and Err are concrete implementations of Result, and Some is a concrete implementation of Option (with None being a singleton for the absence of a value). You will always create an instance of Ok, Err, or Some (or use the None singleton), not directly of Result or Option themselves.

What does "Sealed" mean?

When Result (and Option) are "sealed," it means that only the predefined variants (Ok, Err for Result; Some, None for Option) are allowed to inherit from them. This prevents users of the library from creating their own custom Result or Option types, ensuring that all Result or Option values are one of the intended, known types.

What is the difference between unwrap() and expect()?

  • unwrap(): Attempts to get the contained value. If the operation fails (Err or None), it raises a generic RuntimeError (or the original error for Result.unwrap()).
  • expect(message): Attempts to get the contained value. If the operation fails (Err or None), it raises a RuntimeError that includes your custom message along with the original error, providing more context about why the operation was expected to succeed.

Contributing

Contributions will be welcomed once we reach the release. Please feel free to open issues or submit pull requests freely then.

License

[TBD]

Metadata

Release files for accord-types 0.1.0b3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for accord-types 0.1.0b3
File Size Uploaded Provenance
accord_types-0.1.0b3.tar.gz 21.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for accord-types 0.1.0b3
File Interpreter ABI Platform
accord_types-0.1.0b3-py3-none-any.whl Python 3 none any Details

Total release size: 38.1 kB

Release files / accord_types-0.1.0b3.tar.gz

Download URL accord_types-0.1.0b3.tar.gz
Size 21.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b2e53dd4a74a630af366b77c123d890033b7c7c01263efed4f7e863a0fa2e9ca
BLAKE2b-256 checksum
How to use checksums
700144a8a7b019e3ef709d1be0bf407c622ad82899d1cb1c9a0cc37378cdc999
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / accord_types-0.1.0b3-py3-none-any.whl

Download URL accord_types-0.1.0b3-py3-none-any.whl
Size 17.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b2205bc63426103a11ceea4850c3e0d4bd03e48d3321023a9f3f08852522330e
BLAKE2b-256 checksum
How to use checksums
ac2b9542887e2406c1f31b61e52f0b15e080f30293328b5b0cc4e961e69296d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Security for accord-types 0.1.0b3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page