Skip to content

Fatal1ty/maybe-missing

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

maybe-missing

Build Status Latest Version Python Version License

maybe-missing is a tiny typed helper for one annoyingly real distinction:

  • None means “the caller explicitly sent null”
  • MISSING means “the caller did not send this value at all”

That difference matters in patch APIs, dataclasses, settings layers, and anywhere a database column is nullable but an omitted field should mean “leave it alone”.

Why this exists

Python’s Optional[T] answers only one question: can the value be None?

It does not answer the other question: was there a value in the first place?

That becomes awkward fast:

  • JSON null is a valid payload value
  • a nullable Postgres column may need to be set to NULL intentionally
  • omitting a field in a PATCH request should usually mean “don’t update it”
  • a dataclass default should sometimes mean “missing”, not “defaulted to null”

So this package gives you exactly two public names:

  • Maybe[T]
  • MISSING

And then gets out of your way.

Installation

pip install maybe-missing

Usage

from maybe_missing import Maybe, MISSING


def update_display_name(display_name: Maybe[str | None] = MISSING) -> None:
    if display_name is MISSING:
        print("leave the existing value alone")
    elif display_name is None:
        print("explicitly store NULL")
    else:
        print(f"store {display_name!r}")

Dataclass example

from dataclasses import dataclass

from maybe_missing import Maybe, MISSING


@dataclass(slots=True)
class UserPatch:
    nickname: Maybe[str | None] = MISSING
    bio: Maybe[str | None] = MISSING


def apply_patch(patch: UserPatch) -> None:
    if patch.nickname is not MISSING:
        # update nickname to a string or to NULL
        ...

    if patch.bio is not MISSING:
        # update bio to a string or to NULL
        ...

API example

Imagine a request body for partial updates:

{
  "nickname": null
}

This should mean:

  • nickname was provided
  • its value is explicitly null
  • the server should write NULL

While this body:

{}

should mean:

  • nickname was not provided
  • keep the current value as is

Maybe[T] helps model that cleanly in Python code.

There are only a couple of lines though

Yes.

There are only a couple of lines.

And that’s exactly why it’s more pleasant not to duplicate them across your projects and just do:

from maybe_missing import Maybe, MISSING

Isn’t it?

Typing

The package includes py.typed, so type checkers and IDEs can treat it as a typed distribution.

Compatibility

This package currently targets Python 3.10+.

About

A tiny typed sentinel for distinguishing None from not provided

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages