Skip to main content

optionc

A Scala-inspired Option type for Python, providing Some and Nil types for safe handling of nullable values with functional programming patterns.

Installation

pip install optionc

Quick Start

from optionc import Option, Some, Nil

# Create options (Scala-like)
user_email = Option("john@example.com")  # Some("john@example.com")
empty_value = Option(None)               # Nil()

# Direct construction
valid_user = Some("alice@example.com")
no_user = Nil()

# Safe transformations
result = (user_email
          .map(str.upper)
          .filter(lambda s: '@' in s)
          .map(lambda s: s.split('@')[1]))

print(result.get_or_else("unknown"))  # "EXAMPLE.COM"

Core Usage

Creating Options

from optionc import Option, Some, Nil

# From values
Option("hello")     # Some("hello")
Option(42)          # Some(42)  
Option(None)        # Nil()
Option([])          # Some([]) - empty collections are valid

# Direct construction
Some("direct")      # Some("direct")
Nil()              # Nil()

Transformations

# Safe mapping
result = Some(5).map(lambda x: x * 2)  # Some(10)
empty = Nil().map(lambda x: x * 2)     # Nil()

# Filtering
Some(10).filter(lambda x: x > 5)       # Some(10)
Some(3).filter(lambda x: x > 5)        # Nil()

# Flat mapping for nested operations
def divide_by_two(x):
    return Some(x / 2) if x % 2 == 0 else Nil()

Some(8).flat_map(divide_by_two)        # Some(4.0)
Some(5).flat_map(divide_by_two)        # Nil()

Exception Handling

# Normal methods throw exceptions naturally
Some("hello").map(lambda s: s.nonexistent_method())  # AttributeError

# Safe variants return Nil on exceptions  
Some("hello").map_safe(lambda s: s.nonexistent_method())  # Nil()

# Available safe methods: map_safe, flat_map_safe, filter_safe, foreach_safe

Extracting Values

# Get with default
Some("hello").get_or_else("default")    # "hello"
Nil().get_or_else("default")           # "default"

# Get with lazy default
Nil().get_or_else_get(lambda: compute_default())

# Unsafe get (throws on Nil)
Some("hello").get()                    # "hello"
Nil().get()                           # ValueError

Utility Functions

Common patterns for creating Options from various sources:

from optionc import from_callable, from_dict_get, from_getattr

# From function calls
config = from_callable(lambda: load_config_file())  # Some(config) or Nil()

# From dictionary access
user_name = from_dict_get(data, "name", "anonymous")  # Some("anonymous") if key missing

# From object attributes  
email = from_getattr(user, "email", None)  # Some(email) or Nil()

Real-World Example

from optionc import Option, from_dict_get, from_getattr

def process_user_data(data):
    """Safe user data processing pipeline."""
    return (from_dict_get(data, "user")
            .flat_map(lambda user: from_dict_get(user, "profile"))
            .flat_map(lambda profile: from_dict_get(profile, "email"))
            .filter(lambda email: "@" in email)
            .map(lambda email: email.lower())
            .get_or_else("no-email@example.com"))

# Usage
user_data = {
    "user": {
        "profile": {
            "email": "ALICE@EXAMPLE.COM"
        }
    }
}

result = process_user_data(user_data)  # "alice@example.com"
result = process_user_data({})         # "no-email@example.com"

Decorators

Automatically wrap function returns in Options:

@option

Returns Some(result) for non-None values, Nil() for None. Exceptions propagate normally:

from optionc import option

@option
def find_user(user_id: str) -> User:
    return database.get(user_id)  # Returns Option[User]

@option  
def compute_discount(price: float) -> float:
    if price < 0:
        raise ValueError("Invalid price")
    return price * 0.1

# Usage
user = find_user("123")  # Some(User) or Nil()
discount = compute_discount(100.0)  # Some(10.0)
# compute_discount(-1) raises ValueError

@option_safe

Same as @option but catches exceptions and returns Nil():

from optionc import option_safe

@option_safe
def parse_int(s: str) -> int:
    return int(s)  # Some(42) or Nil() on ValueError

@option_safe
def safe_divide(a: int, b: int) -> float:
    return a / b  # Some(result) or Nil() on ZeroDivisionError

# Usage
result = parse_int("42")        # Some(42)
result = parse_int("invalid")   # Nil()
result = safe_divide(10, 2)     # Some(5.0)
result = safe_divide(10, 0)     # Nil()

Decorator Chaining

Decorators work seamlessly with Option methods:

@option_safe
def extract_domain(email: str) -> str:
    if "@" not in email:
        raise ValueError("Invalid email")
    return email.split("@")[1]

# Chain decorated functions
result = (Option("user@EXAMPLE.com")
          .map(str.lower)
          .flat_map(lambda email: extract_domain(email))
          .map(str.upper))

print(result.get())  # "EXAMPLE.COM"

Why use optionc?

Good for:

  • Null safety: Eliminate None checks and AttributeError exceptions
  • Functional pipelines: Chain operations without intermediate null checks
  • API design: Clear contracts about nullable vs non-nullable values
  • Error handling: Graceful degradation with safe method variants

Integration:

  • Type hints: Full generic type support with Option[T]
  • underscorec: Works seamlessly with functional programming patterns
  • Testing: Deterministic behavior makes testing easier

API Reference

Option Methods

# Checking state
.is_defined()           # True for Some, False for Nil
.is_empty()            # False for Some, True for Nil

# Transformations
.map(func)             # Transform value if present
.map_safe(func)        # Transform value, Nil on exception
.flat_map(func)        # Transform and flatten nested Options  
.flat_map_safe(func)   # Flat map, Nil on exception
.filter(predicate)     # Keep value if predicate matches
.filter_safe(pred)     # Filter, Nil on exception

# Extracting values
.get()                 # Get value (throws on Nil)
.get_or_else(default)  # Get value or default
.get_or_else_get(func) # Get value or call function

# Combining
.or_else(alternative)  # Return self if Some, else alternative
.or_else_get(func)     # Return self if Some, else call function

# Side effects  
.foreach(func)         # Execute function if Some
.foreach_safe(func)    # Execute function, ignore exceptions

Contributing

Development setup:

# Clone and setup
git clone https://github.com/carlyou/optionc.git
cd optionc
uv sync --dev

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov=optionc --cov-report=html

Future Improvements

  • Async support: AsyncOption for asynchronous operations
  • Pattern matching: Python 3.10+ match statement integration
  • Serialization: JSON/pickle support for Some/Nil instances

Metadata

Release files for optionc 0.1.0

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

Source distribution (sdist)

Source distribution for optionc 0.1.0
File Size Uploaded
optionc-0.1.0.tar.gz 64.5 kB Details

Built distribution (wheel)

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

Total release size: 74.1 kB

Release files / optionc-0.1.0.tar.gz

Download URL optionc-0.1.0.tar.gz
Size 64.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e34df504da0d1537b5e9fc4259338be42f4dbdf2e1f46d4ec58915e7b42fc86c
BLAKE2b-256 checksum
How to use checksums
939c5c3c83c7d0827f5eda7ca498224ef9a203d83759d8fc08a7ab918e835cc5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.19

Release files / optionc-0.1.0-py3-none-any.whl

Download URL optionc-0.1.0-py3-none-any.whl
Size 9.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8f3f30d433460e97789ac8717189872288fba76305438009746bd38832809cf9
BLAKE2b-256 checksum
How to use checksums
96d1126e05468d8eb08d9ad70feb61cc546bcf8fc9230a45ca54f30b3a8e8eab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.19

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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