A basic implementation of a maybe/option type in Python, largely inspired by Rust's Option.
Project description
py-maybetype
Documentation: https://py-maybetype.readthedocs.io/en/latest/
PyPI: https://pypi.org/project/py-maybetype/
[!WARNING] I'm not considering any version before 1.0 stable, and breaking changes are likely with each 0.x release. Though I'm using it in my own projects, I wouldn't consider it "production-ready" until
A basic implementation of a maybe/option type in Python, largely inspired by Rust's Option.
This was created as part of a separate project I had been working on, but I decided to make it into
its own package as I wanted to use it elsewhere and its scope grew. This is not meant to be a 1:1
replication or replacement for Rust's Option or Haskell's Maybe, but rather an
interperetation of the idea that I feel works for Python.
Usage
Install with pip:
pip install py-maybetype
Call the maybe() function with a T | None value to return a Maybe[T]—either a Some instance
containing the wrapped value, or the Nothing singleton.
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, Nothing is falsy
assert bool(num1) is True
assert bool(num2) is False
This example in particular can also be done with the Maybe.try_int() class method:
num1: Maybe[int] = Maybe.try_int('5')
num2: Maybe[int] = Maybe.try_int('five')
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 returningNothing, even ifpredicate(None)would returnTrue
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file py_maybetype-0.10.0.tar.gz.
File metadata
- Download URL: py_maybetype-0.10.0.tar.gz
- Upload date:
- Size: 53.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acceaad015aa5fb4055686e0caabbcd32458fd7acc8b9ddf19108a6cd4df10ff
|
|
| MD5 |
7bfb775787f6b635664f19343e955987
|
|
| BLAKE2b-256 |
be5296f4028f4b13f36c3ec7bc0e3bdc3f2bcac20ff22f81a37349cc8e3a12cd
|
Provenance
The following attestation bundles were made for py_maybetype-0.10.0.tar.gz:
Publisher:
publish-to-pypi.yml on svioletg/py-maybetype
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_maybetype-0.10.0.tar.gz -
Subject digest:
acceaad015aa5fb4055686e0caabbcd32458fd7acc8b9ddf19108a6cd4df10ff - Sigstore transparency entry: 1154620922
- Sigstore integration time:
-
Permalink:
svioletg/py-maybetype@a0f37f1ac14c745073954fa539b80b1f564741b4 -
Branch / Tag:
refs/tags/v0.10.0 - Owner: https://github.com/svioletg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@a0f37f1ac14c745073954fa539b80b1f564741b4 -
Trigger Event:
release
-
Statement type:
File details
Details for the file py_maybetype-0.10.0-py3-none-any.whl.
File metadata
- Download URL: py_maybetype-0.10.0-py3-none-any.whl
- Upload date:
- Size: 4.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5fd2af5f188e45e0616b9782d789b253f931460befd6a21ac571acd390e54b99
|
|
| MD5 |
d1f27d0cf185bf3e0eca378c226b8f42
|
|
| BLAKE2b-256 |
4c4c942d74c4e5d73786ce0ba4f711dd3392f91dea0b3dec8325182b84aeedbb
|
Provenance
The following attestation bundles were made for py_maybetype-0.10.0-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on svioletg/py-maybetype
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_maybetype-0.10.0-py3-none-any.whl -
Subject digest:
5fd2af5f188e45e0616b9782d789b253f931460befd6a21ac571acd390e54b99 - Sigstore transparency entry: 1154620926
- Sigstore integration time:
-
Permalink:
svioletg/py-maybetype@a0f37f1ac14c745073954fa539b80b1f564741b4 -
Branch / Tag:
refs/tags/v0.10.0 - Owner: https://github.com/svioletg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@a0f37f1ac14c745073954fa539b80b1f564741b4 -
Trigger Event:
release
-
Statement type: