Skip to main content

Null safe support for Python

Project description

Null Safe Python

Null safe support for Python.

Installation

pip install nullsafe

Quick Start

Normal Python code

o = object()

try:
    value = o.inexistent
    print("accessed")
except AttributeError:
    value = None

With nullsafe:

from nullsafe import undefined, _

o = object()

value = _(o).inexistent

if value is not undefined:
    print("accessed")

Documentation

Basics

There are 5 values importable in nullsafe root:

class NullSafeProxy: (o: T)

Receives an object o on instantiation.

Proxy class for granting nullsafe abilities to an object.

class NullSafe: ()

No argument needed.

Nullish class with with nullsafe abilities. Instances will have a falsy boolean evaluation, equity comparison (==) to None and instance of NullSafe returns True, otherwise False. Identity comparison (is) to None will return False.

variable undefined: NullSafe

Instance of Nullsafe, this instance will be returned for all nullish access in a proxied object, enabling identity comparison value is undefined for code clarity.

function nullsafe: (o: T) -> T

Receives an object o as argument.

Helper function that checks if object is nullish and return the proxied object.

return undefined if o is None or undefined, otherwise return the proxied object NullSafeProxy[T].

This function is generic typed ((o: T) -> T), code autocompletions and linters functionalities will remain. Disclaimer: If the object was not typed before proxy, it obviously won't come out typed out of the blue.

function _: (o: T) -> T (alias to nullsafe)

Alias to nullsafe, used for better code clarity.

The examples shown will be using _ instead of nullsafe for code clarity. For better understanding, the Javascript equivalents will be shown as comments.

Implementation

Nullsafe abilities are granted after proxying an object through NullSafeProxy. To proxy an object pass it through _() or nullsafe(). Due to language limitation, the implementation does not follow the "return the first nullish value in chain", instead it "extend the a custom nullish value until the end of chain". Inexistent values of a proxied object and its subsequent values in chain will return undefined.

Import

from nullsafe import undefined, _

Usage

There are various way to get a nullsafe proxied object.

Null safe attribute access

Proxied object doing a possibly AttributeError access.

o = SomeClass()

# o.inexistent
assert _(o).inexistent is undefined
assert _(o).inexistent == None # Same to all below
assert not _(o).inexistent # Same to all below

# o.inexistent?.nested
assert _(o).inexistent.nested is undefined

# o.existent.inexistent?.nested
assert _(o.existent).inexistent.nested is undefined

# o.maybe?.inexistent?.nested
assert _(_(o).maybe).inexistent.nested is undefined

Null safe item access

Proxied object doing a possibly KeyError access.

o = SomeClass() # dict works too !

# o.inexistent
assert _(o)["inexistent"] is undefined
assert _(o)["inexistent"] == None # Same to all below
assert not _(o)["inexistent"] # Same to all below

# o.inexistent?.nested
assert _(o)["inexistent"]["nested"] is undefined

# o.existent.inexistent?.nested
assert _(o["existent"])["inexistent"]["nested"] is undefined

# o.maybe?.inexistent?.nested
assert _(_(o)["maybe"])["inexistent"]["nested"] is undefined

Null safe post evaluation

Possibly None or undefined object doing possibly AttributeError or KeyError access.

Note: This only works if the seeking value is accessible, see limitations

o = SomeClass() # dict works too !
o.nay = None

# o.nay?.inexistent
assert _(o.nay).inexistent is undefined
assert _(o.nay).inexistent == None # Same to all below
assert not _(o.nay).inexistent # Same to all below

# o.nay?.inexistent.nested
assert _(o.nay).inexistent.nested is undefined
o = SomeClass() # dict works too !
o["nay"] = None

# o.nay?.inexistent
assert _(o["nay"])["inexistent"] is undefined
assert not _(o["nay"])["inexistent"]

# o.nay?.inexistent.nested
assert _(o["nay"])["inexistent"]["nested"] is undefined
assert not _(o["nay"])["inexistent"]["nested"]

Combined usage

Of course you can combine different styles.

assert _(o).inexistent["inexistent"].inexistent.inexistent["inexistent"]["inexistent"] is undefined

Limitations

List of limitations that you may encounter.

undefined behavior

undefined is actually an instance of NullSafe, the actual mechanism used for nullsafe chaining, it cannot self rip the nullsafe functionality when the chain ends (because it doesn't know), so this following actually possible and probably not the wanted behavior.

val = _(o).inexistent

assert val.another_inexistent is undefined

Post evaluation

In other languages like Javascript, it checks for each item in the chain and return undefined on the first nullish value, which in fact is post-evaluated. This is not possible in python because it raises an AttributeError or KeyError on access attempt, unless it returns None (see one of the available usage), so it must proxy the instance that may contain the attr or key before accessing.

try:
    val = _(o.inexistent).nested # AttributeError: '<type>' object has no attribute 'inexistent'
except AttributeError:
    assert True
assert _(o).inexistent.nested is undefined

Contributing

Contributions welcomed ! Make sure it passes current tests tho.

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

nullsafe-0.1.0.tar.gz (5.6 kB view details)

Uploaded Source

Built Distribution

nullsafe-0.1.0-py3-none-any.whl (6.1 kB view details)

Uploaded Python 3

File details

Details for the file nullsafe-0.1.0.tar.gz.

File metadata

  • Download URL: nullsafe-0.1.0.tar.gz
  • Upload date:
  • Size: 5.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.5.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.9.5

File hashes

Hashes for nullsafe-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3f3e87f25299fb496ebf912ce74358a0422f3c0e18a09ec89c577b08a038a7a3
MD5 dc61ebf9b4678009e574ee5a64ff81cb
BLAKE2b-256 de7e73b7513805e0c8b99a58d7d6407b255f454ec1c5b216ffcb2a68cc494462

See more details on using hashes here.

File details

Details for the file nullsafe-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nullsafe-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.5.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.9.5

File hashes

Hashes for nullsafe-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5eab1c29d901d10dae38869167a41c12ca035f9c5ad1b1eb7e48836d7c1a46b4
MD5 c2b66edd5e7f3b6b3c6bd3d71a204141
BLAKE2b-256 31fc942e2ad50eb933a9fc0defcef709c94659251db2340a466ca67e61512195

See more details on using hashes here.

Supported by

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