Skip to main content

Is one None not enough for you? There's more

Project description

Downloads Downloads Coverage Status Lines of code Hits-of-Code Test-Package Python versions PyPI version Checked with mypy Ruff DeepWiki

logo

The None constant built into Python is convenient for client code, but it is often insufficient when creating libraries. The fact is that this makes it impossible to distinguish situations where a value is undefined from situations where it is defined as undefined. Does that sound too abstract?

In fact, the problem of this distinction is found everywhere in library development. Sentinel objects are used to resolve it, and many modules from the standard library define their own. For example, the dataclasses library defines a special MISSING constant for such cases. This is used to separate the cases when the user has not set a default value from the case when he has set None as the default value.

However, we can't all use sentinel objects from some built-in module if we don't need the functionality of that module. Until the PEP has been adopted on this topic, it is better to use a special package containing only this primitive. Such a package is denial. It defines just such an object: None for situations where you need to distinguish None as a value from the user, and None as a designation that something is really undefined. This value should not fall "outside", into the user's space, it should remain only inside the libraries implementations. In addition, this library offers a special class that allows you to create your own sentinels.

Table of contents

Installation

Install it:

pip install denial

You can also quickly try out this and other packages without having to install using instld.

The second None

This library defines an object that is proposed to be used in almost the same way as a regular None. This is how it is imported:

from denial import InnerNone

This object is equal only to itself:

print(InnerNone == InnerNone)
#> True
print(InnerNone == False)
#> False

This object is also an instance of InnerNoneType class (an analog of NoneType, however, is not inherited from this), which makes it possible to check through isinstance:

from denial import InnerNoneType

print(isinstance(InnerNone, InnerNoneType))
#> True

It is recommended to use the InnerNone object inside libraries where a value close to None is required, but meaning a situation where the value is not really set, rather than set as None. This object should be completely isolated from the user code space. None of the public methods of your library should return this object.

Your own None objects

If None and InnerNone are not enough for you, you can create your own similar objects by instantiating InnerNoneType:

sentinel = InnerNoneType()

This object will also be equal only to itself:

print(sentinel == sentinel)
#> True

print(sentinel == InnerNoneType())  # Comparison with another object of the same type
#> False
print(sentinel == InnerNone)  # Also comparison with another object of the same type
#> False
print(sentinel == None)  # Comparison with None
#> False
print(sentinel == 123)  # Comparison with an arbitrary object
#> False

You can also pass an integer or a string to the class constructor. An InnerNoneType object is equal to another such object with the same argument:

print(InnerNoneType(123) == InnerNoneType(123))
#> True
print(InnerNoneType('key') == InnerNoneType('key'))
#> True

print(InnerNoneType(123) == InnerNoneType(1234))
#> False
print(InnerNoneType('key') == InnerNoneType('another key'))
#> False
print(InnerNoneType(123) == InnerNoneType())
#> False
print(InnerNoneType(123) == 123)
#> False

💡 Any InnerNoneType objects can be used as keys in dictionaries.

Type hinting

When used in a type hint, the expression None is considered equivalent to type(None).

Official typing documentation

None is a special value for which Python type checkers make an exception, allowing it to be used as an annotation of its own type. Unfortunately, this behavior cannot be reproduced without changing the internal implementation of existing type checkers, which I would not expect until the PEP is adopted.

Therefore, it is suggested to use class InnerNoneType as a type annotation:

def function(default: int | InnerNoneType):
    ...

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

denial-0.0.3.tar.gz (6.2 kB view details)

Uploaded Source

Built Distribution

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

denial-0.0.3-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

Details for the file denial-0.0.3.tar.gz.

File metadata

  • Download URL: denial-0.0.3.tar.gz
  • Upload date:
  • Size: 6.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for denial-0.0.3.tar.gz
Algorithm Hash digest
SHA256 5dd63ad7c20a9fd98cf3d2bf86a27fbb0c8f421ed2a1df5ae9d241d49008d363
MD5 cc4f7ecfd34c61d454cac04c470f4f12
BLAKE2b-256 debe2d2a2b960deb2b22b32b7c5ef60a7143204991536852b1cb4b5d1f02d89c

See more details on using hashes here.

Provenance

The following attestation bundles were made for denial-0.0.3.tar.gz:

Publisher: release.yml on pomponchik/denial

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

File details

Details for the file denial-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: denial-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 5.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for denial-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 0e3bedcfc481fddb87c3297bc1f4abcb5aadf3733348f6a289aabc5e2f08cf60
MD5 45644fceba71a0a82ffa6d81e4a237e4
BLAKE2b-256 4ad35974fed873c16489b70c8aa0397144a45947936591b0eff91ec176c001a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for denial-0.0.3-py3-none-any.whl:

Publisher: release.yml on pomponchik/denial

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