nulltype


Namenulltype JSON
Version 2.3.1 PyPI version JSON
download
home_pagehttps://bitbucket.org/jeunice/nulltype
SummaryNull values and sentinels like (but not) None, False & True
upload_time2018-06-03 22:01:01
maintainer
docs_urlNone
authorJonathan Eunice
requires_python
licenseApache License 2.0
keywords null none nothing empty false true singleton sentinel
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
| |travisci| |version| |versions| |impls| |wheel| |coverage| |br-coverage|

.. |travisci| image:: https://api.travis-ci.org/jonathaneunice/nulltype.svg
    :target: http://travis-ci.org/jonathaneunice/nulltype

.. |version| image:: http://img.shields.io/pypi/v/nulltype.svg?style=flat
    :alt: PyPI Package latest release
    :target: https://pypi.org/project/nulltype

.. |versions| image:: https://img.shields.io/pypi/pyversions/nulltype.svg
    :alt: Supported versions
    :target: https://pypi.org/project/nulltype

.. |impls| image:: https://img.shields.io/pypi/implementation/nulltype.svg
    :alt: Supported implementations
    :target: https://pypi.org/project/nulltype

.. |wheel| image:: https://img.shields.io/pypi/wheel/nulltype.svg
    :alt: Wheel packaging support
    :target: https://pypi.org/project/nulltype

.. |coverage| image:: https://img.shields.io/badge/test_coverage-100%25-6600CC.svg
    :alt: Test line coverage
    :target: https://pypi.org/project/nulltype

.. |br-coverage| image:: https://img.shields.io/badge/branch_coverage-100%25-6600CC.svg
    :alt: Test branch coverage
    :target: https://pypi.org/project/nulltype

Helps define 'null' values and sentinels parallel to, but different from,
Python built-ins such as ``None``, ``False``, and ``True``.

``None`` is a great `sentinel value <http://en.wikipedia.org/wiki/Sentinel_value>`_
and a classic implementation of the
`null object pattern <http://en.wikipedia.org/wiki/Null_Object_pattern>`_.

But there are times that you need more than one nullish value to represent
different aspects of emptiness. "Nothing there" is logically different from
"undefined," "prohibited," "end of data," and other kinds of "null."

``nulltype`` helps you easily represent different aspects of emptiness in a way
that doesn't overload ``None`` (or ``False``, ``0``, ``{}``, ``[]``, ``""``, or
any of the other possible "there's nothing here!" values). It helps create
designated identifiers with specific meanings such as ``Passthrough``,
``Prohibited``, and ``Undefined``.

On the off chance that you need truish sentinels that aren't ``True``, it will
help you do that too. And it will do so in an easily-consumed,
right-off-the-shelf, fully-tested tested way.

Usage
=====

::

    from nulltype import NullType

    Void = NullType('Void')

    # following just to show it's working
    assert bool(Void) == False
    assert len(EmpVoidty) == 0
    assert list(Void) == []
    assert Void.some_attribute is Empty
    assert Void[22] is Nothing
    assert Void("hey", 12) is Empty

You can create as many custom null values as you like. For convenience, several
default values, ``Empty``, ``Null``, and ``Nothing``, are exported. That way,
if you don't really want to create your own, you can easily import a
pre-constituted null value::

    from nulltype import Empty

The Power of Nothing
====================

Alternate null types can be particularly useful when parsing
data or traversing data structures which might or might not be
present. This is common in dealing with the data returned by
`REST <http://en.wikipedia.org/wiki/Representational_state_transfer>`_
APIs, for instance.

As one example, `the documentation for Google's Gmail API <https://developers.google.com/gmail/api/quickstart/quickstart-python>`_
suggests the following code::

    threads = gmail_service.users().threads().list(userId='me').execute()
    if threads['threads']:
        for thread in threads['threads']:
            print 'Thread ID: %s' % (thread['id'])

There is a lot going on there just to avoid a problematic deference.
If instead you have a ``Nothing`` null type defined, the code is
shorter (and avoids an extra, very transient variable)::

    results = gmail_service.users().threads().list(userId='me').execute()
    for thread in results.get('threads', Nothing):
        print 'Thread ID: %s' % (thread['id'])

Three lines versus four may not seem like a big advantage, but the value
increases with the complexity of the task. Many such "if it's there, then..."
constructs are deeply nested when dealing with API results, XML parse trees,
and other fundamentally nested information sources. Saving a guard condition
on every one of the nesting levels adds up quickly.

While you could almost do this in stock Python, unlike ``Nothing``, ``None`` is
not iterable. You might use an empty list ``[]`` (or an equivalent global such
as ``EMPTYLIST``) as the alternative value for the ``get`` method. Going by the
documentation of many parsers and APIs, however, such uses aren't broadly
idiomatic in today's Python community. The ``EMPTYLIST`` approach also is very
specific to routines returning lists, whereas the "go ahead, get it if you can"
``nulltype`` model works well for longer chains of access::

    results.get("payload", Nothing).get("headers", Nothing)

will return the correct object if it's there, but ``Nothing`` otherwise.
And if you then try to test it (e.g. with ``if`` or a logical expression)
or iterate over it (e.g. with ``for``), it will act as though it's an empty
list, or ``False``--whatever is most useful in a given context. Whether you're
iterating, indexing, dereferencing, calling, or otherwise accessing it, a
``NullType`` is unperturbed.

``Nothing`` isn't nothing. It's something that will simplify your code.

General Sentinels and Distinguished Values
==========================================

While ``nulltype`` is frequently used to define new kinds of "empty" values,
it's actually more general. Beyond different forms of 'null', ``NullType``
instances are good general-purpose sentinels or designated values. Instead of
the old::

    class MySentinelClass(object):
        pass

Use::

    MySentinel = NullType('MySentinel')

That gives you a value with known truthiness properties and a nicer
printed representation.::

    >>> print MySentinelClass               # fugly
    <class '__main__.MySentinelClass'>

    >>> print MySentinel                    # just right
    MySentinel

On the off chance you want a sentinel value that is
`truthy <https://en.wikipedia.org/wiki/Truthiness>`_ rather than falsey /
empty, use ``NonNullType``, a companion to ``NullType`` that operates in
almost the exact same way, but that evaluates as true.::

    from nulltype import NonNullType

    Full = NonNullType('Full')

    assert bool(Full) is True
    assert len(Full) == 1
    assert list(Full) == [Full]
    assert Full.some_attribute is Full
    assert Full[22] is Full
    assert Full("hey", 12) is Full

Experience suggests that nullish sentinels are generally adequate and
preferable. And the "everything folds back to the same value" nature of even
``NonNullType`` gives a somewhat null-like, or at least non-reactive, nature.
But if you do want a true-ish sentinel, there it is.


Uniqueness
==========

``NullType`` instances are meant to be `singletons
<http://en.wikipedia.org/wiki/Singleton_pattern>`_, with just one per program.
They almost are, though technically multiple ``NullType`` instances are
reasonable, making it more of a `multiton pattern
<http://en.wikipedia.org/wiki/Multiton_pattern>`_.

The uniqueness of each singleton is currently not enforced, making it a usage
convention rather than strict law. With even minimal care, this is a problem
roughly 0% of the time.


Notes
=====

* Successfully packaged for, and
  tested against, all late-model versions of Python: 2.6, 2.7, 3.3,
  3.4, 3.5, 3.6, and 3.7 pre-release, as well as recent builds of PyPy and PyPy3. 

* See ``CHANGES.yml`` for the complete Change Log.

* Automated multi-version testing managed with `pytest
  <http://pypi.python.org/pypi/pytest>`_, `pytest-cov
  <http://pypi.python.org/pypi/pytest-cov>`_,
  `coverage <https://pypi.python.org/pypi/coverage/4.0b1>`_
  and `tox
  <http://pypi.python.org/pypi/tox>`_. Continuous integration testing
  with `Travis-CI <https://travis-ci.org/jonathaneunice/nulltype>`_.
  Packaging linting with `pyroma <https://pypi.python.org/pypi/pyroma>`_.

* Similar modules include `sentinels <http://pypi.org/project/sentinels>`_ and `null
  <http://pypi.org/project/null>`_. Of these, I prefer ``sentinels``
  because it is clearly Python 3 ready, includes a ``pickle``
  mechanism.  `noattr <https://pypi.org/project/noattr>`_ is a
  new alternative.

* For a module that uses the null value ``Empty`` to make the parsing of 
  JSON and other data formats easier, see 
  `items <https://pypi.org/project/items>`_ 

* The author, `Jonathan Eunice <mailto:jonathan.eunice@gmail.com>`_ or
  `@jeunice on Twitter <http://twitter.com/jeunice>`_,
  welcomes your comments and suggestions.

Installation
============

To install or upgrade to the latest version::

    pip install -U nulltype

You may need to prefix this with ``sudo`` to authorize installation on Unix,
Linux, and macOS. In environments without super-user privileges, you may want
to use ``pip``'s ``--user`` option, to install only for a single user, rather
than system-wide. On a system with multiple versions of Python, you may also
need to use specific ``pip3`` or ``pip2`` commands instead of the stock
``pip``. As a backup, running pip as a Python module can save your sanity in
complex cases where ``pip`` versions aren't working well as standalone
commands::

    python3.6 -m pip install -U nulltype

Testing
=======

To run the module tests, use one of these commands::

    tox                # normal run - speed optimized
    tox -e py27        # run for a specific version only (e.g. py27, py34)
    tox -c toxcov.ini  # run full coverage tests

            

Raw data

            {
    "_id": null,
    "home_page": "https://bitbucket.org/jeunice/nulltype",
    "name": "nulltype",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "null none nothing Empty False True singleton sentinel",
    "author": "Jonathan Eunice",
    "author_email": "jonathan.eunice@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/2f/ce/92289851364b7f816a839c8064aac06c01f3a3ecf33ab04adf9d0a0ab66a/nulltype-2.3.1.zip",
    "platform": "",
    "description": "\n| |travisci| |version| |versions| |impls| |wheel| |coverage| |br-coverage|\n\n.. |travisci| image:: https://api.travis-ci.org/jonathaneunice/nulltype.svg\n    :target: http://travis-ci.org/jonathaneunice/nulltype\n\n.. |version| image:: http://img.shields.io/pypi/v/nulltype.svg?style=flat\n    :alt: PyPI Package latest release\n    :target: https://pypi.org/project/nulltype\n\n.. |versions| image:: https://img.shields.io/pypi/pyversions/nulltype.svg\n    :alt: Supported versions\n    :target: https://pypi.org/project/nulltype\n\n.. |impls| image:: https://img.shields.io/pypi/implementation/nulltype.svg\n    :alt: Supported implementations\n    :target: https://pypi.org/project/nulltype\n\n.. |wheel| image:: https://img.shields.io/pypi/wheel/nulltype.svg\n    :alt: Wheel packaging support\n    :target: https://pypi.org/project/nulltype\n\n.. |coverage| image:: https://img.shields.io/badge/test_coverage-100%25-6600CC.svg\n    :alt: Test line coverage\n    :target: https://pypi.org/project/nulltype\n\n.. |br-coverage| image:: https://img.shields.io/badge/branch_coverage-100%25-6600CC.svg\n    :alt: Test branch coverage\n    :target: https://pypi.org/project/nulltype\n\nHelps define 'null' values and sentinels parallel to, but different from,\nPython built-ins such as ``None``, ``False``, and ``True``.\n\n``None`` is a great `sentinel value <http://en.wikipedia.org/wiki/Sentinel_value>`_\nand a classic implementation of the\n`null object pattern <http://en.wikipedia.org/wiki/Null_Object_pattern>`_.\n\nBut there are times that you need more than one nullish value to represent\ndifferent aspects of emptiness. \"Nothing there\" is logically different from\n\"undefined,\" \"prohibited,\" \"end of data,\" and other kinds of \"null.\"\n\n``nulltype`` helps you easily represent different aspects of emptiness in a way\nthat doesn't overload ``None`` (or ``False``, ``0``, ``{}``, ``[]``, ``\"\"``, or\nany of the other possible \"there's nothing here!\" values). It helps create\ndesignated identifiers with specific meanings such as ``Passthrough``,\n``Prohibited``, and ``Undefined``.\n\nOn the off chance that you need truish sentinels that aren't ``True``, it will\nhelp you do that too. And it will do so in an easily-consumed,\nright-off-the-shelf, fully-tested tested way.\n\nUsage\n=====\n\n::\n\n    from nulltype import NullType\n\n    Void = NullType('Void')\n\n    # following just to show it's working\n    assert bool(Void) == False\n    assert len(EmpVoidty) == 0\n    assert list(Void) == []\n    assert Void.some_attribute is Empty\n    assert Void[22] is Nothing\n    assert Void(\"hey\", 12) is Empty\n\nYou can create as many custom null values as you like. For convenience, several\ndefault values, ``Empty``, ``Null``, and ``Nothing``, are exported. That way,\nif you don't really want to create your own, you can easily import a\npre-constituted null value::\n\n    from nulltype import Empty\n\nThe Power of Nothing\n====================\n\nAlternate null types can be particularly useful when parsing\ndata or traversing data structures which might or might not be\npresent. This is common in dealing with the data returned by\n`REST <http://en.wikipedia.org/wiki/Representational_state_transfer>`_\nAPIs, for instance.\n\nAs one example, `the documentation for Google's Gmail API <https://developers.google.com/gmail/api/quickstart/quickstart-python>`_\nsuggests the following code::\n\n    threads = gmail_service.users().threads().list(userId='me').execute()\n    if threads['threads']:\n        for thread in threads['threads']:\n            print 'Thread ID: %s' % (thread['id'])\n\nThere is a lot going on there just to avoid a problematic deference.\nIf instead you have a ``Nothing`` null type defined, the code is\nshorter (and avoids an extra, very transient variable)::\n\n    results = gmail_service.users().threads().list(userId='me').execute()\n    for thread in results.get('threads', Nothing):\n        print 'Thread ID: %s' % (thread['id'])\n\nThree lines versus four may not seem like a big advantage, but the value\nincreases with the complexity of the task. Many such \"if it's there, then...\"\nconstructs are deeply nested when dealing with API results, XML parse trees,\nand other fundamentally nested information sources. Saving a guard condition\non every one of the nesting levels adds up quickly.\n\nWhile you could almost do this in stock Python, unlike ``Nothing``, ``None`` is\nnot iterable. You might use an empty list ``[]`` (or an equivalent global such\nas ``EMPTYLIST``) as the alternative value for the ``get`` method. Going by the\ndocumentation of many parsers and APIs, however, such uses aren't broadly\nidiomatic in today's Python community. The ``EMPTYLIST`` approach also is very\nspecific to routines returning lists, whereas the \"go ahead, get it if you can\"\n``nulltype`` model works well for longer chains of access::\n\n    results.get(\"payload\", Nothing).get(\"headers\", Nothing)\n\nwill return the correct object if it's there, but ``Nothing`` otherwise.\nAnd if you then try to test it (e.g. with ``if`` or a logical expression)\nor iterate over it (e.g. with ``for``), it will act as though it's an empty\nlist, or ``False``--whatever is most useful in a given context. Whether you're\niterating, indexing, dereferencing, calling, or otherwise accessing it, a\n``NullType`` is unperturbed.\n\n``Nothing`` isn't nothing. It's something that will simplify your code.\n\nGeneral Sentinels and Distinguished Values\n==========================================\n\nWhile ``nulltype`` is frequently used to define new kinds of \"empty\" values,\nit's actually more general. Beyond different forms of 'null', ``NullType``\ninstances are good general-purpose sentinels or designated values. Instead of\nthe old::\n\n    class MySentinelClass(object):\n        pass\n\nUse::\n\n    MySentinel = NullType('MySentinel')\n\nThat gives you a value with known truthiness properties and a nicer\nprinted representation.::\n\n    >>> print MySentinelClass               # fugly\n    <class '__main__.MySentinelClass'>\n\n    >>> print MySentinel                    # just right\n    MySentinel\n\nOn the off chance you want a sentinel value that is\n`truthy <https://en.wikipedia.org/wiki/Truthiness>`_ rather than falsey /\nempty, use ``NonNullType``, a companion to ``NullType`` that operates in\nalmost the exact same way, but that evaluates as true.::\n\n    from nulltype import NonNullType\n\n    Full = NonNullType('Full')\n\n    assert bool(Full) is True\n    assert len(Full) == 1\n    assert list(Full) == [Full]\n    assert Full.some_attribute is Full\n    assert Full[22] is Full\n    assert Full(\"hey\", 12) is Full\n\nExperience suggests that nullish sentinels are generally adequate and\npreferable. And the \"everything folds back to the same value\" nature of even\n``NonNullType`` gives a somewhat null-like, or at least non-reactive, nature.\nBut if you do want a true-ish sentinel, there it is.\n\n\nUniqueness\n==========\n\n``NullType`` instances are meant to be `singletons\n<http://en.wikipedia.org/wiki/Singleton_pattern>`_, with just one per program.\nThey almost are, though technically multiple ``NullType`` instances are\nreasonable, making it more of a `multiton pattern\n<http://en.wikipedia.org/wiki/Multiton_pattern>`_.\n\nThe uniqueness of each singleton is currently not enforced, making it a usage\nconvention rather than strict law. With even minimal care, this is a problem\nroughly 0% of the time.\n\n\nNotes\n=====\n\n* Successfully packaged for, and\n  tested against, all late-model versions of Python: 2.6, 2.7, 3.3,\n  3.4, 3.5, 3.6, and 3.7 pre-release, as well as recent builds of PyPy and PyPy3. \n\n* See ``CHANGES.yml`` for the complete Change Log.\n\n* Automated multi-version testing managed with `pytest\n  <http://pypi.python.org/pypi/pytest>`_, `pytest-cov\n  <http://pypi.python.org/pypi/pytest-cov>`_,\n  `coverage <https://pypi.python.org/pypi/coverage/4.0b1>`_\n  and `tox\n  <http://pypi.python.org/pypi/tox>`_. Continuous integration testing\n  with `Travis-CI <https://travis-ci.org/jonathaneunice/nulltype>`_.\n  Packaging linting with `pyroma <https://pypi.python.org/pypi/pyroma>`_.\n\n* Similar modules include `sentinels <http://pypi.org/project/sentinels>`_ and `null\n  <http://pypi.org/project/null>`_. Of these, I prefer ``sentinels``\n  because it is clearly Python 3 ready, includes a ``pickle``\n  mechanism.  `noattr <https://pypi.org/project/noattr>`_ is a\n  new alternative.\n\n* For a module that uses the null value ``Empty`` to make the parsing of \n  JSON and other data formats easier, see \n  `items <https://pypi.org/project/items>`_ \n\n* The author, `Jonathan Eunice <mailto:jonathan.eunice@gmail.com>`_ or\n  `@jeunice on Twitter <http://twitter.com/jeunice>`_,\n  welcomes your comments and suggestions.\n\nInstallation\n============\n\nTo install or upgrade to the latest version::\n\n    pip install -U nulltype\n\nYou may need to prefix this with ``sudo`` to authorize installation on Unix,\nLinux, and macOS. In environments without super-user privileges, you may want\nto use ``pip``'s ``--user`` option, to install only for a single user, rather\nthan system-wide. On a system with multiple versions of Python, you may also\nneed to use specific ``pip3`` or ``pip2`` commands instead of the stock\n``pip``. As a backup, running pip as a Python module can save your sanity in\ncomplex cases where ``pip`` versions aren't working well as standalone\ncommands::\n\n    python3.6 -m pip install -U nulltype\n\nTesting\n=======\n\nTo run the module tests, use one of these commands::\n\n    tox                # normal run - speed optimized\n    tox -e py27        # run for a specific version only (e.g. py27, py34)\n    tox -c toxcov.ini  # run full coverage tests\n",
    "bugtrack_url": null,
    "license": "Apache License 2.0",
    "summary": "Null values and sentinels like (but not) None, False & True",
    "version": "2.3.1",
    "split_keywords": [
        "null",
        "none",
        "nothing",
        "empty",
        "false",
        "true",
        "singleton",
        "sentinel"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "39ec735ecf059fb68121beb507ab41fb",
                "sha256": "16ae565745118e37e0558441f5821c76351d8c3a789640b5bca277cf65b2271b"
            },
            "downloads": -1,
            "filename": "nulltype-2.3.1-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "39ec735ecf059fb68121beb507ab41fb",
            "packagetype": "bdist_wheel",
            "python_version": "3.6",
            "requires_python": null,
            "size": 11054,
            "upload_time": "2018-06-03T22:01:04",
            "upload_time_iso_8601": "2018-06-03T22:01:04.030484Z",
            "url": "https://files.pythonhosted.org/packages/00/0f/47dde1a3cceac9858da0bfb92d2279bf5f993ed075b72983e92efc297db3/nulltype-2.3.1-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "55f30edd641788e4e596dd0acb915c54",
                "sha256": "64aa3cb2ab5e904d1b37175b9b922bea268c13f9ce32e3d373313150ab5ef272"
            },
            "downloads": -1,
            "filename": "nulltype-2.3.1.zip",
            "has_sig": false,
            "md5_digest": "55f30edd641788e4e596dd0acb915c54",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 20119,
            "upload_time": "2018-06-03T22:01:01",
            "upload_time_iso_8601": "2018-06-03T22:01:01.450702Z",
            "url": "https://files.pythonhosted.org/packages/2f/ce/92289851364b7f816a839c8064aac06c01f3a3ecf33ab04adf9d0a0ab66a/nulltype-2.3.1.zip",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2018-06-03 22:01:01",
    "github": false,
    "gitlab": false,
    "bitbucket": true,
    "bitbucket_user": "jeunice",
    "bitbucket_project": "nulltype",
    "lcname": "nulltype"
}
        
Elapsed time: 0.01823s