{ "info": { "author": "Eddie Antonio Santos", "author_email": "easantos@ualberta.ca", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "*************************************************\nsentinel \u2014 create sentinel and singleton objects\n*************************************************\n\n|Tests| |PyPI version|\n\n.. |Tests| image:: https://github.com/eddieantonio/sentinel/workflows/Test%20and%20Lint/badge.svg\n :target: https://github.com/eddieantonio/sentinel/actions?query=workflow%3A%22Test+and+Lint%22\n.. |PyPI version| image:: https://img.shields.io/pypi/v/sentinel\n :target: https://pypi.org/project/sentinel/\n\nCreates simple sentinel objects.\n\n\nInstall\n=======\n\nBasic features::\n\n pip install sentinel\n\nwith extra magic features powered by python-varname_::\n\n pip install 'sentinel[varname]'\n\n\nWhat is a sentinel?\n===================\n\nSentinels_ are singleton_ objects that typically represent some\nterminating (end) condition or have a special, symbolic meaning. Python's built-in\n``None`` is a sentinel. Python also has other sentinels like ``NotImplemented`` and\n``Ellipsis``.\n\nIf you want to create your own sentinels, use this library! Make your calls to\n``dict.get()`` more meaningful! You can replace the ``object()`` idiom with a sentinel:\n\n.. code-block:: python\n\n d = {\"a\": 1, \"b\": None}\n\n # Before sentinel:\n missing = object()\n if d.get(\"c\", missing) is missing:\n ... # do some stuff\n\n # After sentinel:\n Missing = sentinel.create()\n if d.get(\"c\", Missing) is Missing:\n ... # do some stuff\n\n\nFeatures\n--------\n\n - sentinels are unique\n - sentinels are singletons \u2014 the **only** instance of their own anonymous class\n - sentinels can be used with ``is`` comparisons\n - sentinels can be used with ``pickle``\n - sentinels can be used with ``copy.deepcopy``\n - you can **add** arbitrary attributes and methods to sentinels\n - sentinels have a nice, self-documenting ``__repr__``!\n\nUsage\n=====\n\nCreate a sentinel:\n\n>>> import sentinel\n>>> MySentinel = sentinel.create(\"MySentinel\")\n>>> Sentinel\nSentinel\n\nIf you have python-varname_ installed, or installed this module using\n``pip install 'sentinel[varname]'``, ``sentinel.create()`` can infer the name\nfrom the assignment expression:\n\n.. code-block:: python\n\n import sentinel\n\n MySentinel = sentinel.create()\n\n print(MySentinel) # prints `MySentinel`\n\n\nExample\n-------\n\nSentinels are useful when other objects such as ``None``, ``False``,\n``0``, ``-1``, are valid values within some data structure. For example, setting\ndefault values when all other values are valid with:\n``dict.setdefault()``:\n\n.. code-block:: python\n\n d = {\"stdout\": None, \"stdin\": 0, \"EOF\": -1}\n\n MissingEntry = sentinel.create()\n\n [d.setdefault(key, MissingEntry) for key in (\"stdin\", \"stdout\", \"stderr\")]\n [0, None, MissingEntry]\n\nAlternatively, using ``dict.get()`` when fetching values:\n\n>>> d = {\"stdout\": None, \"stdin\": 0, \"EOF\": -1}\n>>> d.get(\"stdout\", MissingEntry)\nNone\n>>> d.get(\"stdin\", MissingEntry)\n0\n>>> d.get(\"stderr\", MissingEntry)\nMissingEntry\n\nSince a new sentinel can never occur in the original dictionary, you can tell which\nentries are missing or unset in a dictionary in a self-documenting way:\n\n.. code-block:: python\n\n Unset = sentinel.create()\n if d.get(\"stdin\", Unset) is Unset:\n stdin = 0 # some reasonable default\n\n\nAdding extra methods and class attributes\n-----------------------------------------\n\nSentinels may also inherit from base classes, or implement extra methods.\n\nConsider a binary search tree with two kinds of nodes: interior nodes\n(``Node``) which contain some payload and leaves (``Leaf``), which simply\nterminate traversal.\n\nTo create singleton leaf which implements a ``search`` method and an\n``is_leaf`` property, you may provide any extra class attributes in the\n``cls_dict`` keyword argument. The following is a full example of both\nthe singleton ``Leaf`` and its ``Node`` counterpart:\n\n.. code-block:: python\n\n def _search_leaf(self, key):\n raise KeyError(key)\n\n Leaf = sentinel.create('Leaf', cls_dict={\n 'search': _search_leaf,\n 'is_leaf': property(lambda self: True)\n })\n\n class Node(object):\n def __init__(self, key, payload, left=Leaf, right=Leaf):\n self.left = left\n self.right = right\n self.key = key\n self.payload = payload\n\n def search(self, key):\n if key < self.key:\n return self.left.search(key)\n elif key > self.key:\n return self.right.search(key)\n else:\n return self.payload\n\n is_leaf = property(lambda: false)\n\nExample usage:\n\n>>> tree = Node(2, 'bar', Node(1, 'foo'), Node(3, 'baz'))\n>>> tree.search(1)\n'foo'\n>>> tree.search(4)\nTraceback (most recent call last):\n ...\nKeyError: 2\n\n\nContributing\n============\n\nThis project uses Poetry_. To contribute to the codebase, make sure to `install poetry`_,\nWith Poetry installed, clone then repo, then within the repo directory, install the developer dependencies::\n\n $ poetry install --extras varname\n\nNext, I recommend you do all development tasks within the ``poetry shell``::\n\n $ poetry shell\n (sentinel-nUnrocCf-py3.9) $ black .\n (sentinel-nUnrocCf-py3.9) $ pytest\n\n.. _Sentinels: http://en.wikipedia.org/wiki/Sentinel_nodes\n.. _singleton: http://en.wikipedia.org/wiki/Singleton_pattern\n.. _Poetry: https://python-poetry.org/\n.. _install poetry: https://python-poetry.org/docs/#installation\n.. _python-varname: https://github.com/pwwang/python-varname\n", "description_content_type": "text/x-rst", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/eddieantonio/sentinel", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "sentinel", "package_url": "https://pypi.org/project/sentinel/", "platform": "", "project_url": "https://pypi.org/project/sentinel/", "project_urls": { "Homepage": "https://github.com/eddieantonio/sentinel", "Repository": "https://github.com/eddieantonio/sentinel.git" }, "release_url": "https://pypi.org/project/sentinel/0.3.0/", "requires_dist": [ "varname (>=0.1); extra == \"varname\"" ], "requires_python": ">=3.6,<4.0", "summary": "Create sentinel objects, akin to None, NotImplemented, Ellipsis", "version": "0.3.0", "yanked": false, "yanked_reason": null }, "last_serial": 9027512, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "a0c07702d81d11a1d72f58b9eaa24072", "sha256": "8d0a59adfeced6fe9c8a2add2db35d5e9737769a511a230f2d095ff3be775c9d" }, "downloads": -1, "filename": "sentinel-0.1.0.tar.gz", "has_sig": false, "md5_digest": "a0c07702d81d11a1d72f58b9eaa24072", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3281, "upload_time": "2014-08-22T23:37:08", "upload_time_iso_8601": "2014-08-22T23:37:08.201274Z", "url": "https://files.pythonhosted.org/packages/0e/08/96620cf74ffb5c60a1ad275bc59d909c187d55084a03e3505cdb4e571fb5/sentinel-0.1.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "29993a01be2fa1d46a567d745d9c05fe", "sha256": "c00ba2a4f240ea4c5414059a696d6e128730272cb2c631b2eff42e86da1f89b3" }, "downloads": -1, "filename": "sentinel-0.1.1.tar.gz", "has_sig": false, "md5_digest": "29993a01be2fa1d46a567d745d9c05fe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3894, "upload_time": "2014-08-23T05:24:12", "upload_time_iso_8601": "2014-08-23T05:24:12.838683Z", "url": "https://files.pythonhosted.org/packages/2e/12/867f97b68c2a541f1e0de6b3b8ff52a2c2bef8d88228efc885ad07f20968/sentinel-0.1.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "4926a5a602addec8bc37b3cd88437959", "sha256": "9cdd949268b4010adedef2a2287f00ba70f4195afe56031f699321291937e667" }, "downloads": -1, "filename": "sentinel-0.1.2-py2-none-any.whl", "has_sig": false, "md5_digest": "4926a5a602addec8bc37b3cd88437959", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 5495, "upload_time": "2019-10-22T03:01:15", "upload_time_iso_8601": "2019-10-22T03:01:15.399428Z", "url": "https://files.pythonhosted.org/packages/3b/1e/84b84d409a592a4580badc04223776ed6efc4711b7b8f6c8d7c3c11691d0/sentinel-0.1.2-py2-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "e81cec582f7fab0ad334fc5e6cf31438", "sha256": "c7aeee3f57c56a8e52771fc64230345deecd62c48debbbe1f1aca453439741d0" }, "downloads": -1, "filename": "sentinel-0.1.2.tar.gz", "has_sig": false, "md5_digest": "e81cec582f7fab0ad334fc5e6cf31438", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4893, "upload_time": "2019-10-22T03:01:16", "upload_time_iso_8601": "2019-10-22T03:01:16.778806Z", "url": "https://files.pythonhosted.org/packages/d2/e7/9e40edaeca0e73790044815932e56bbe9d3bb9bd6f22df6e3f8e8ce6c539/sentinel-0.1.2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "35a2339baf7fd8657f510d1418248b67", "sha256": "270785db1c52a33640d127b5ff51f0883b120137e1083c507697eca6143041a2" }, "downloads": -1, "filename": "sentinel-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "35a2339baf7fd8657f510d1418248b67", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 5391, "upload_time": "2020-12-30T21:52:58", "upload_time_iso_8601": "2020-12-30T21:52:58.074289Z", "url": "https://files.pythonhosted.org/packages/e1/29/96e17891e1d2a5d8ddfc61503cbc2bfc244ecb6a75258a0f2c4420f28d43/sentinel-0.2.0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "459de809493767e3910b463c120ab600", "sha256": "8b7a7426031c0545db895e0d8c585ef34d4ba9c6724243a4c36c838dfa211747" }, "downloads": -1, "filename": "sentinel-0.2.0.tar.gz", "has_sig": false, "md5_digest": "459de809493767e3910b463c120ab600", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 5556, "upload_time": "2020-12-30T21:52:59", "upload_time_iso_8601": "2020-12-30T21:52:59.225466Z", "url": "https://files.pythonhosted.org/packages/55/0d/2810fcc477163d961419ba913b1ddda369d2547f70e33525dd4d6cea1b6a/sentinel-0.2.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.2.1a0": [ { "comment_text": "", "digests": { "md5": "c615b59d209c93a0110dbab70fe79186", "sha256": "85bca409b63018a5327eb8ce600d21258c6d2fd4527d32bdc76155daff48223f" }, "downloads": -1, "filename": "sentinel-0.2.1a0-py3-none-any.whl", "has_sig": false, "md5_digest": "c615b59d209c93a0110dbab70fe79186", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 5219, "upload_time": "2020-12-30T21:05:06", "upload_time_iso_8601": "2020-12-30T21:05:06.185247Z", "url": "https://files.pythonhosted.org/packages/e7/11/acf4dee9f4cfaa6b78b31c983ced4f4580a8790f49e5e803f4e1964e7bba/sentinel-0.2.1a0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "3c9a8c1290f58c87d74c22dbe21338e7", "sha256": "b77c156d12cbad13291a41547da0dc81f9dc53b62064e3f662e2e11e7a7b27b6" }, "downloads": -1, "filename": "sentinel-0.2.1a0.tar.gz", "has_sig": false, "md5_digest": "3c9a8c1290f58c87d74c22dbe21338e7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 5314, "upload_time": "2020-12-30T21:05:07", "upload_time_iso_8601": "2020-12-30T21:05:07.001517Z", "url": "https://files.pythonhosted.org/packages/3f/77/7d0cea8c0ae9c0b8b090255c2d6b728fd54aee5504847a48f11d5ff24033/sentinel-0.2.1a0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "dbae886319717882d49ce20c65e084ae", "sha256": "bd8710dd26752039c668604f6be2aaf741b56f7811c5924a4dcdfd74359244f3" }, "downloads": -1, "filename": "sentinel-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "dbae886319717882d49ce20c65e084ae", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 5999, "upload_time": "2020-12-31T20:36:58", "upload_time_iso_8601": "2020-12-31T20:36:58.684459Z", "url": "https://files.pythonhosted.org/packages/df/60/6436b0d8e47feeb2b56ae8a702994d4edb110be9c7310ea6e8918a1a85b0/sentinel-0.3.0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "74e2328b52dc7aa412ab5ec2ff339ed8", "sha256": "f28143aa4716dbc8f6193f5682176a3c33cd26aaae05d9ecf66c186a9887cc2d" }, "downloads": -1, "filename": "sentinel-0.3.0.tar.gz", "has_sig": false, "md5_digest": "74e2328b52dc7aa412ab5ec2ff339ed8", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 6451, "upload_time": "2020-12-31T20:36:59", "upload_time_iso_8601": "2020-12-31T20:36:59.830162Z", "url": "https://files.pythonhosted.org/packages/5b/78/0c8e4b41ee425be92888bc118af7c15fc7b771a7e495d7b48b223cd6c382/sentinel-0.3.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3.0a1": [ { "comment_text": "", "digests": { "md5": "c408856e402a2a6d72e4cf0491ea6984", "sha256": "2cb17f4821a32cdda29422df7da34ba67b489d252e53fee9b1ab1cef48139be0" }, "downloads": -1, "filename": "sentinel-0.3.0a1-py3-none-any.whl", "has_sig": false, "md5_digest": "c408856e402a2a6d72e4cf0491ea6984", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 6018, "upload_time": "2020-12-31T20:28:00", "upload_time_iso_8601": "2020-12-31T20:28:00.148475Z", "url": "https://files.pythonhosted.org/packages/bc/08/f0bc71e922aaf2dc1b65b2a1869d247a32411413a7cf4be3babf821a137c/sentinel-0.3.0a1-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "3ec3ac151f8897c71c6213da53048a2c", "sha256": "6d7168563466572fcd7e19db46091013a1f85e7c02e0b8cf601c1286d9987e63" }, "downloads": -1, "filename": "sentinel-0.3.0a1.tar.gz", "has_sig": false, "md5_digest": "3ec3ac151f8897c71c6213da53048a2c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 6467, "upload_time": "2020-12-31T20:28:01", "upload_time_iso_8601": "2020-12-31T20:28:01.242069Z", "url": "https://files.pythonhosted.org/packages/49/25/701117b8d57631cccbebb4ea991578ef4988bf39218a303c86ea937484fd/sentinel-0.3.0a1.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "dbae886319717882d49ce20c65e084ae", "sha256": "bd8710dd26752039c668604f6be2aaf741b56f7811c5924a4dcdfd74359244f3" }, "downloads": -1, "filename": "sentinel-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "dbae886319717882d49ce20c65e084ae", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 5999, "upload_time": "2020-12-31T20:36:58", "upload_time_iso_8601": "2020-12-31T20:36:58.684459Z", "url": "https://files.pythonhosted.org/packages/df/60/6436b0d8e47feeb2b56ae8a702994d4edb110be9c7310ea6e8918a1a85b0/sentinel-0.3.0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "74e2328b52dc7aa412ab5ec2ff339ed8", "sha256": "f28143aa4716dbc8f6193f5682176a3c33cd26aaae05d9ecf66c186a9887cc2d" }, "downloads": -1, "filename": "sentinel-0.3.0.tar.gz", "has_sig": false, "md5_digest": "74e2328b52dc7aa412ab5ec2ff339ed8", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 6451, "upload_time": "2020-12-31T20:36:59", "upload_time_iso_8601": "2020-12-31T20:36:59.830162Z", "url": "https://files.pythonhosted.org/packages/5b/78/0c8e4b41ee425be92888bc118af7c15fc7b771a7e495d7b48b223cd6c382/sentinel-0.3.0.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }