Skip to main content

A basic implementation of a maybe/option type in Python, largely modeled after by Rust's Option and Result types.

Project description

py-maybetype

Linting Testing PyPI publishing

Documentation: https://py-maybetype.readthedocs.io/en/latest/

PyPI: https://pypi.org/project/py-maybetype/

[!WARNING] This project is in beta, and breaking changes are likely with each 0.x release.

A basic implementation of a maybe/option type in Python, largely aiming for parity (within reason) with Rust's Option and Result types implemented in a way that makes sense for Python, with a few additional methods.

Usage

Install with pip:

pip install py-maybetype

Call the maybe() function with a T | None value to return either a Some[T] instance containing the wrapped value, or the Nothing singleton. You can also directly use the Some constructor or the Nothing singleton explicitly e.g. when returning a value from a function. Maybe only serves as a base class to provide methods for Some and Nothing and to be used for typing, it should not be instanced directly. If it is, MaybeInstanceError is raised.

Nothing is an instance of the NothingType class, and should be used instead of creating new NothingType instances since all are functionally identical. NothingTypeInitError if the class is instanced more than once.

from maybetype import Maybe, maybe

# Only the maybe() function should be used,
# the Maybe class is only imported here for type annotations

def try_int(x: str) -> int | None:
    """Attempts to convert a string of digits into an `int`, returning `None` if not possible."""
    try:
        return int(x)
    except ValueError:
        return None

num1: Maybe[int] = maybe(try_int('5'))
num2: Maybe[int] = maybe(try_int('five'))

print(num1.unwrap()) # 5
print(num2.unwrap()) # (raises ValueError)

# Some() instances are always truthy, NothingType() is falsy

assert bool(num1) is True
assert bool(num2) is False

The maybe constructor can be given an optional predicate argument to specify a custom condition for which Some(value) is returned. This argument must be a Callable that returns bool, where returning False causes the constructor to return Nothing.

[!NOTE] maybe(None) will always return Nothing, even if predicate(None) would return True

import re
import uuid

from maybetype import maybe

def is_valid_uuid(s: str) -> bool:
    return re.match(r"[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}|[0-9a-f]{32}", s) is not None

assert maybe('3b1bcc3a-41d5-49a5-8273-10cc605e31f9', is_valid_uuid)
assert maybe('3b1bcc3a41d549a5827310cc605e31f9', is_valid_uuid)
assert not maybe('qwertyuiopasdfghjklzxcvbnm', is_valid_uuid)
assert not maybe('nf0cmmdq-l0gt-rq5a-upry-706trht3ocv9', is_valid_uuid)

Maybe instances can also be used in match/case pattern matching to access the wrapped value, like so:

from maybetype import maybe, Some

match maybe(1):
    case Some(val):
        print('Value: ', val)
    case _: # "case Nothing:" also works, but just matching else in this case will be identical
        print('No value')

Other examples

Converting a str | None timestamp into a datetime object if not None, otherwise returning None:

from datetime import datetime
from maybetype import maybe

assert maybe('2025-09-06T030000').then(datetime.fromisoformat) == datetime(2025, 9, 6, 3, 0)

assert maybe(None).then(datetime.fromisoformat) is None

assert maybe('' or None).then(datetime.fromisoformat) is None
# Maybe does not treat falsy values as None, only strictly x-is-None values
# Without `or None` here, datetime.fromisoformat would have raised a ValueError

Converting a str | None timestamp into a datetime object if not None, then ensuring that date meets certain criteria:

from datetime import datetime
from maybetype import maybe

assert maybe('2025-09-06T030000').and_then(datetime.fromisoformat).test(lambda dt: dt.year > 2024)

assert not maybe('2024-09-06T030000').and_then(datetime.fromisoformat).test(lambda dt: dt.year > 2024)

match maybe('2025-09-06T030000').and_then(datetime.fromisoformat).test(lambda dt: dt.year > 2024):
    case Some(date):
        ... # Do something with the date
    case _:
        ... # Do something else

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py_maybetype-0.13.0.tar.gz (67.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

py_maybetype-0.13.0-py3-none-any.whl (10.1 kB view details)

Uploaded Python 3

File details

Details for the file py_maybetype-0.13.0.tar.gz.

File metadata

  • Download URL: py_maybetype-0.13.0.tar.gz
  • Upload date:
  • Size: 67.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for py_maybetype-0.13.0.tar.gz
Algorithm Hash digest
SHA256 fd596d574f368c7d95c8eefcb7c518f50f43ad9e8ba893371e585bb5bfd50978
MD5 9514873a653889aa1175e8e88475e98d
BLAKE2b-256 9fb685d7ca78f47cc7e2ff0097dc95e9fab6728dfbc80daf613d3c4f1fff30fb

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_maybetype-0.13.0.tar.gz:

Publisher: publish-to-pypi.yml on svioletg/py-maybetype

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file py_maybetype-0.13.0-py3-none-any.whl.

File metadata

  • Download URL: py_maybetype-0.13.0-py3-none-any.whl
  • Upload date:
  • Size: 10.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for py_maybetype-0.13.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a3cca8403b1e291816ffedf777718b90c3eab87ad9a2eb8b038cd93211f9bab2
MD5 1d1f24227a47aa42defeef868e235798
BLAKE2b-256 56a26744c2206cffa076cd34c97f441fce1155226f30747640cb6d11d75b2864

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_maybetype-0.13.0-py3-none-any.whl:

Publisher: publish-to-pypi.yml on svioletg/py-maybetype

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page