py-maybetype
Documentation: https://py-maybetype.readthedocs.io/en/latest/
PyPI: https://pypi.org/project/py-maybetype/
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.
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
Release files for py-maybetype 0.14.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| py_maybetype-0.14.0.tar.gz | 67.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| py_maybetype-0.14.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 78.0 kB
Release files / py_maybetype-0.14.0.tar.gz
| Download URL | py_maybetype-0.14.0.tar.gz |
|---|---|
| Size | 67.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e44acf3fa5e605bced653bd1aa3ed660ed000ee10db799d6a55a157409d61691
|
|
BLAKE2b-256 checksum How to use checksums |
2a346beb4faf2e2b70e2b8bf1f4f6b478b227c00bf930b97898c49b5a89d6a9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 10, 2026.
Transparency logRelease files / py_maybetype-0.14.0-py3-none-any.whl
| Download URL | py_maybetype-0.14.0-py3-none-any.whl |
|---|---|
| Size | 10.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
741d54b82c135573cefe218c1374accd40fcd0e9b69f1c3814bc088902a2a7a5
|
|
BLAKE2b-256 checksum How to use checksums |
f0619956326d4a9e9d319bf2f2d01c8dec8f188400087eddca2b6f031b336416
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 10, 2026.
Transparency log