{ "info": { "author": "Alexander Kozhevnikov", "author_email": "mentalisttraceur@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.3", "Programming Language :: Python :: 2.4", "Programming Language :: Python :: 2.5", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.0", "Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: IronPython", "Programming Language :: Python :: Implementation :: Jython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: Stackless" ], "description": "Python ``raise`` as a Function\n==============================\n\nRaise exceptions with a function instead of a statement.\n\nProvides a minimal, clean and portable interface for raising exceptions\nwith all the advantages of functions over syntax.\n\n\nWhy\n---\n\nI want to be able to work with exceptions in a way that is:\n\n1. *Intuitive* to use and see in code.\n2. *Generic* and *flexible*, empowering *reuse*.\n3. *Portable* to all versions of Python I might want to use.\n\nPython is a great language, and modern Python in particular takes a\nnice approach to exceptions.\n\nIn my code, I've often found myself writing interfaces that combine\nthe intuitive nature of Python 3's ``raise`` and ``with_traceback``,\nthe generic and flexible pattern of raising exceptions in other\ncoroutines or threads of execution as exemplified by the ``throw``\nmethod on Python generators, and the inherently portable and powerfully\nreusable and composable form of a basic function.\n\nThe interface provided by this module, the function signature taking\nan ``exception`` (either an instance *or* a type) and an optional\n``traceback`` instance, is what I found myself arriving at that met all\nof these criteria. It has served me well in code that I've worked on,\nand I'm submitting it to the world in the hope that others will either\nfind it useful and build upon it or point out flaws in my approach.\n\nIf you have a more specific \"why\" question, I recorded my reasons for a\nlot of the specific choices here in the `Design Decisions`_ section.\n\n\nVersioning\n----------\n\nThis library's version numbers follow the `SemVer 2.0.0 specification\n`_.\n\nThe current version number is available in the variable ``__version__``\nas is normal for Python modules.\n\n\nInstallation\n------------\n\n::\n\n pip install raise\n\n**If** you need or want to get it *manually*, or you need the \"no\ntraceback\" variant, see the `Advanced/Manual Installation`_ section\nfor suggestions/tips.\n\n\nUsage\n-----\n\nImport the ``raise_`` function from the ``raise_`` module:\n\n.. code:: python\n\n from raise_ import raise_\n\nThen you can raise things in a fairly intuitive manner:\n\n1. Raising an exception:\n\n .. code:: python\n\n raise_(Exception('foo'))\n\n You can of course also pass an exception type instead of an\n exception instance as the first argument to ``raise_``.\n\n2. Raising an exception with a traceback:\n\n .. code:: python\n\n raise_(Exception('foo'), my_traceback_object)\n\n\nPortability\n-----------\n\nPortable to all releases of both Python 3 and Python 2.\n\n(The oldest tested is 2.5, but it will likely work on all Python 2\nversions and probably on even earlier versions.)\n\nFor implementations of Python that do not support raising with a custom\ntraceback, a \"no traceback\" variant can be installed manually.\n\n\nAdvanced/Manual Installation\n----------------------------\n\nThere are three recommended ways of installing this manually, depending\non your needs:\n\n1. If you're installing it into the library path for your Python system\n as a whole or adding it into the source tree of a project that is\n not meant to be compatible to both Python 3 and Python 2 or older,\n you can just take either ``raise3.py`` or ``raise2.py`` and save it\n *as* ``raise_.py``.\n\n2. If you're adding it into the source tree of a project that should\n work with both Python 3 and Python 2 and older, copy the whole\n ``raise_`` directory.\n\n3. If you're using a Python implementation that does not support raising\n exceptions with a custom traceback, take the ``raise_no_traceback.py``\n file and save it *as* ``raise_.py``.\n\nAll of these methods have the advantage that your code can just do\n``from raise_ import raise_`` and it'll just work consistently,\nwithout version-detecting boilerplate or hardcoding the version number\nin the module name (which is an implementation detail).\n\nYou are of course welcome to just copy-paste the tiny ``raise_``\nfunction definition into your code, just keep in mind the compatibility\nissues involved: your code will only work without modification on Python\nversions compatible with the version you chose, and Python 2's version\ncauses a SyntaxError in Python 3, which is uncatchable within the same\nfile.\n\n\nDesign Decisions\n----------------\n\n* Allow ``exception`` to be either an instance or a type, because this\n convention is *very* ingrained in Python.\n\n* Do not currently implement an equivalent to Python 3's ``except\n ... from ...`` syntax.\n\n Ultimately, this syntax just assigns one exception as an attribute\n on another exception.\n\n This strikes me as *complecting* two different jobs together: raising an\n exception instance and *initializing* an exception instance with a\n ``__cause__`` attribute.\n\n I note that generators' ``throw`` method does not have support for\n a separe \"from\"/\"cause\" argument either. Perhaps it should, but then\n everything implementing this interface would have to implement extra\n logic to handle that extra argument.\n\n Instead I would advocate for a separate interface for setting the\n ``__cause__`` or ``__context__`` attributes on exceptions such as\n extending ``BaseException`` with ``with_cause`` and ``with_context``\n methods.\n\n* Do not use the convention of taking separate ``type`` and ``value``\n arguments because it seems like a counter-intuitive and inappropriate\n convention for *raising* an exception.\n\n Python 3 dropped support for separate ``type`` and ``value`` from the\n ``raise`` statement, so it seems enough people responsible for the\n language already agree with this assessment.\n\n Also fully/properly supporting all semantics/variations that ``raise``\n allowed before Python 3 would bloat the code excessively.\n\n* Do not support Python 3's ``__traceback__`` behavior: we do not try\n to emulate it in Python 2 and we intentionally suppress Python 3's\n automatic implicit use of ``__traceback__`` when raising, because:\n\n * When an insufficiently careful coder (almost all of us almost all\n of the time) has code work one way on one platform, they assume it\n will work that way consistently on other platforms.\n\n * Emulating Python 3's behavior on Python 2 creates extra potential\n for **wrong** behavior: a native ``except`` called between code\n that uses the emulation will result in references to stale traceback\n objects on the exception being used.\n\n * The following two mantras feel like useful heuristics here:\n\n Perfection is reached not when there's nothing left to add, but\n when there is nothing left to take away.\n\n and\n\n It is far easier to introduce a feature than to remove one.\n\n * I want to emphasize this again because it's a lesson I learned from\n the portability hellscapes of Bourne shell and C: if it differs\n among implementations it *will be* the source of bugs and pain.\n\n* Using two separate implementation files and an ``__init__.py`` that\n imports one or the other avoids using ``exec``.\n\n We want to avoid using ``exec`` because it brings its own slew of\n portability problems, because it makes the code messier (nesting code\n in strings), *and* because I wanted the implementations for each\n version of the language to be *independently* reusable from a trivial\n copy.\n\n* Using a ``raise_`` package directory and ``__init__.py`` because it\n makes ``setup.py`` and pip install stupid simple rather than trying\n to figure out a way to only install the right file as ``raise_.py``.\n\n While I would *love* to implement it so that a ``pip install`` from\n Python 3 only installed ``raise3.py`` as ``raise_.py``, ditto for 2,\n this would make the packaging stuff far less trivial.\n\n* ``__init__.py`` tries ``BaseException.with_traceback`` and uses\n ``AttributeError`` to fail instead of ``import raise_.raise2`` and\n ``SyntaxError`` to fail because it conceptually highlights the\n primacy of Python 3 as the ought-to-be-default case.\n\n I also think it's *conceptually* cleaner to *not* first parse and\n interpret a file only to abort on a syntax error. Performance-wise\n it's negligible and thus a non-issue though.\n\n Sadly this breaks ``pylint`` on Python 3, because it unconditionally\n imports the `raise2` and aborts upon getting the syntax error. But on\n a tiny module like this, that's not a major issue. I manually worked\n around it to run ``pylint`` by commenting out the offending import,\n and I don't foresee enough changes to make that a hassle.\n\n* We don't do anything about ``flake8`` complaining that ``__version__``\n is imported but not used because this module is too tiny for me to\n justify throwing in some linter-specific disabling comment just to\n quell one spurious warning in an otherwise ``flake8``-silent file.\n\n* Not allowing ``exception`` or ``traceback`` to be arbitrary callables:\n Even though it has value for all/most arguments of all/many functions,\n it is precisely because of this that it is best implemented as a\n general composable tool (such a as a decorator/wrapper function).\n\n If done, it ought to be done for both exception and traceback, so not\n supporting it for one implies not supporting it for the other.\n\n Not supporting it is reason to not accidentally let it work despite\n being undocumented, because again, people assume that if it works it\n is supported.\n\n This is why the code uses an affirmative result from ``issubtype``\n to decide whether to call ``exception`` to construct an instance,\n instead of any other approach, even though this forces calling\n ``isinstance`` first to avoid a spurious ``TypeError``.\n\n* To aid portability of code to Python implementations that do not\n support specifying a custom traceback when raising, allowing\n ``traceback`` to be silently accepted but ignored helps writing code\n that portably follows \"progressive enhancement\" or \"graceful\n degradation\" practices: tracebacks are properly used where possible,\n but ignored where not.\n\n This is **not** always the wisest choice: some features and behavior\n are relied on for security, correctness, or debugging, and in those\n cases the inability to fulfill the contract of an interface must not\n be silently hidden.\n\n Because of this, the \"no traceback\" variant is \"opt-in\": if you're\n using it, you deliberately included it into your project, or a\n dependency of yours did.\n\n* Null out *both* arguments in the ``finally`` inside of ``raise_``\n to alleviate the potential for reference cycles being made by the\n traceback, which references all locals in each stack frame.\n\n ``traceback`` is obvious: it will cyclically reference itself.\n\n ``exception`` **might** reference ``traceback`` either directly or\n indirectly, and we have no way to know for sure that it doesn't.\n\n* Not nulling out the arguments to ``raise_`` in the \"no traceback\"\n variant because the reference cycle depends on having a reference\n to the traceback data within the call stack itself.\n\n Also, Python implementations that need the \"no traceback\" variant\n tend to be diversely incompatible: even ``try``-``finally`` does\n not work in all of them.\n\n So it seems like the \"no traceback\" variant doesn't need this fix,\n and it is a safer bet to not mess with it until a need is found.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/mentalisttraceur/python-raise", "keywords": "", "license": "0BSD (BSD Zero Clause License)", "maintainer": "", "maintainer_email": "", "name": "raise", "package_url": "https://pypi.org/project/raise/", "platform": "", "project_url": "https://pypi.org/project/raise/", "project_urls": { "Homepage": "https://github.com/mentalisttraceur/python-raise" }, "release_url": "https://pypi.org/project/raise/1.1.1/", "requires_dist": null, "requires_python": "", "summary": "Raise exceptions with a function instead of a statement.", "version": "1.1.1" }, "last_serial": 4860248, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "6fb2b7553de8f1c261eba76a519be999", "sha256": "5f20f6ace1e777e8c2bf0569d28d085f12ba43a7dce027795357021e7caf3176" }, "downloads": -1, "filename": "raise-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "6fb2b7553de8f1c261eba76a519be999", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 12886, "upload_time": "2018-03-19T12:25:19", "url": "https://files.pythonhosted.org/packages/5b/7b/d411150ce57cdf53a563d64d14f7c40c09809cba9cf44ef3a6783a3c3f9a/raise-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1ea941a175679e5f1fff555cb2b3632f", "sha256": "a8a8c16cbeb6f11dfb44c4e89547ebf3746c8823326d0be360389a9d3cea4329" }, "downloads": -1, "filename": "raise-1.0.0.tar.gz", "has_sig": false, "md5_digest": "1ea941a175679e5f1fff555cb2b3632f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7253, "upload_time": "2018-03-19T12:25:22", "url": "https://files.pythonhosted.org/packages/17/60/9ab6f25c4681ad8431cc5ce449cb1aa1e46fdb6f90a2a98c0e82fd1f24e3/raise-1.0.0.tar.gz" } ], "1.0.0.post1": [ { "comment_text": "", "digests": { "md5": "52f3dc06144e62301f8eba309f036fda", "sha256": "0480868e9ed4175a933deb814d42a3b6a5dbc13a820baa9e9e6b85cb51144109" }, "downloads": -1, "filename": "raise-1.0.0.post1-py3-none-any.whl", "has_sig": false, "md5_digest": "52f3dc06144e62301f8eba309f036fda", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 12977, "upload_time": "2018-03-19T18:32:49", "url": "https://files.pythonhosted.org/packages/2f/32/6f84e7dfb783289b06dae47454accbbad43328d64d0f66a52f527161cc2a/raise-1.0.0.post1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "251b173e75a78e4eed24357503331b21", "sha256": "36a89fe8d7404fba562f4b180e76950069d902177c66af8de66589b523c43dc3" }, "downloads": -1, "filename": "raise-1.0.0.post1.tar.gz", "has_sig": false, "md5_digest": "251b173e75a78e4eed24357503331b21", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7307, "upload_time": "2018-03-19T18:32:53", "url": "https://files.pythonhosted.org/packages/d8/64/e549765f2da39a526e455e8b325df6d5c3d9009d47cea39249d5fb0697da/raise-1.0.0.post1.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "971b18141d023b3f5c98e9cc5fcf7bb7", "sha256": "5023020062ee16d72fbb557c7e89ffca39412f52fe78a0a4009cefe0a99c503e" }, "downloads": -1, "filename": "raise-1.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "971b18141d023b3f5c98e9cc5fcf7bb7", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 12907, "upload_time": "2018-04-25T06:35:07", "url": "https://files.pythonhosted.org/packages/72/67/8592b38695bc1f284a647a85de4bfb9ef10cde8133bc73c4841883df455a/raise-1.0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5b68ae3e81b7654a398d6ff2e9b642d1", "sha256": "5987be62164609d1b42a9acb9bfb78ccd3b916e17eeda37e75435e6c6bb1795a" }, "downloads": -1, "filename": "raise-1.0.1.tar.gz", "has_sig": false, "md5_digest": "5b68ae3e81b7654a398d6ff2e9b642d1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7369, "upload_time": "2018-04-25T06:35:09", "url": "https://files.pythonhosted.org/packages/71/67/4e87bfd0e130348431fcf506995e4927bd8353cb788be3c3a497bfb71969/raise-1.0.1.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "dffd043e3df8f646a6c8e62404215764", "sha256": "2dc7122064b1566522ab107664d3ca4c84d3417f48a77a3818c2b5a994e85ff0" }, "downloads": -1, "filename": "raise-1.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "dffd043e3df8f646a6c8e62404215764", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 12919, "upload_time": "2018-04-25T07:22:15", "url": "https://files.pythonhosted.org/packages/c8/b0/18a6df05d1237f555616f24d44e817ad311e73d904a235098b1e0d3e5da3/raise-1.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "96f0595f496b211ccecafcd26ba6a7af", "sha256": "5e417344b43c8ceacafee3c478ce2718d295add4b39432539f1f1d3c94b3c33b" }, "downloads": -1, "filename": "raise-1.1.0.tar.gz", "has_sig": false, "md5_digest": "96f0595f496b211ccecafcd26ba6a7af", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7358, "upload_time": "2018-04-25T07:22:17", "url": "https://files.pythonhosted.org/packages/6a/80/ae3ce29ed831ab5ecafdae0b9f8511ac8407106694f39485893c465d8f9e/raise-1.1.0.tar.gz" } ], "1.1.0.post1": [ { "comment_text": "", "digests": { "md5": "c8d34d899dcce17e31a7faa9372db577", "sha256": "adc5ee65254894d4ae4dec6a41ff4f21a31ded1c43ad90d1d706f9244e54c07a" }, "downloads": -1, "filename": "raise-1.1.0.post1-py3-none-any.whl", "has_sig": false, "md5_digest": "c8d34d899dcce17e31a7faa9372db577", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13615, "upload_time": "2019-02-18T06:44:12", "url": "https://files.pythonhosted.org/packages/ce/e3/e2db68b0552528c539ea33eef03f7bd9753b9dd32c2f1a8cbf1d94ab3918/raise-1.1.0.post1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6ff199576a57ee1cb88f229a4195bb3e", "sha256": "a42a3ecee8748b8c66ecec30c4617376af1875f6a6658d19dc4c1523f34df0eb" }, "downloads": -1, "filename": "raise-1.1.0.post1.tar.gz", "has_sig": false, "md5_digest": "6ff199576a57ee1cb88f229a4195bb3e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7778, "upload_time": "2019-02-18T06:44:15", "url": "https://files.pythonhosted.org/packages/49/0a/9534e95e88c51c025b075efea9e642c1ec0f32f87729c70b15dbc9cf66e5/raise-1.1.0.post1.tar.gz" } ], "1.1.0.post2": [ { "comment_text": "", "digests": { "md5": "2ece2afc475ece79a7d17cc0ec6dec56", "sha256": "d51186d886b8301bed200c132b6ad1a1f45eae13a52ad30efc0128114eac071d" }, "downloads": -1, "filename": "raise-1.1.0.post2-py3-none-any.whl", "has_sig": false, "md5_digest": "2ece2afc475ece79a7d17cc0ec6dec56", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13623, "upload_time": "2019-02-18T06:57:30", "url": "https://files.pythonhosted.org/packages/e4/af/009b4abc8d43c6c6b387ade1b4ec59714775b387012176a461734dcdb379/raise-1.1.0.post2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c6d2b55c599869c5f58d56ac799d1e20", "sha256": "4879df1cc21b518f0a43f49f9a6f73d7f8c820f7009a1b9e10344d8c402f9511" }, "downloads": -1, "filename": "raise-1.1.0.post2.tar.gz", "has_sig": false, "md5_digest": "c6d2b55c599869c5f58d56ac799d1e20", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7772, "upload_time": "2019-02-18T06:57:32", "url": "https://files.pythonhosted.org/packages/d5/51/5c905d0cbe1e9b4096f28c9644f12c572928fe44f9f415e809fe0144fadb/raise-1.1.0.post2.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "76cbd9b981cf41a044562648356eded4", "sha256": "f4dd2f2d28705d210c7d4bd09872233af93b0925fe0db504835d3d7c7eecd015" }, "downloads": -1, "filename": "raise-1.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "76cbd9b981cf41a044562648356eded4", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14024, "upload_time": "2019-02-24T07:27:12", "url": "https://files.pythonhosted.org/packages/3f/b2/78b09e154f718514f9b5c382fd064a5bd7e36bd45f25c1c94316085ae4c4/raise-1.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "212f2f51c5825f03fb64aed1936df877", "sha256": "c8257e97134fc69263346c6224028b86a83dc1a2ff8a3b719edbd476c8ddb9d6" }, "downloads": -1, "filename": "raise-1.1.1.tar.gz", "has_sig": false, "md5_digest": "212f2f51c5825f03fb64aed1936df877", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8064, "upload_time": "2019-02-24T07:12:27", "url": "https://files.pythonhosted.org/packages/29/a4/5ee57b4c9f848976c2ec541d94c8a8b59c13663f1f1d412ddc0d5775c92f/raise-1.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "76cbd9b981cf41a044562648356eded4", "sha256": "f4dd2f2d28705d210c7d4bd09872233af93b0925fe0db504835d3d7c7eecd015" }, "downloads": -1, "filename": "raise-1.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "76cbd9b981cf41a044562648356eded4", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 14024, "upload_time": "2019-02-24T07:27:12", "url": "https://files.pythonhosted.org/packages/3f/b2/78b09e154f718514f9b5c382fd064a5bd7e36bd45f25c1c94316085ae4c4/raise-1.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "212f2f51c5825f03fb64aed1936df877", "sha256": "c8257e97134fc69263346c6224028b86a83dc1a2ff8a3b719edbd476c8ddb9d6" }, "downloads": -1, "filename": "raise-1.1.1.tar.gz", "has_sig": false, "md5_digest": "212f2f51c5825f03fb64aed1936df877", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8064, "upload_time": "2019-02-24T07:12:27", "url": "https://files.pythonhosted.org/packages/29/a4/5ee57b4c9f848976c2ec541d94c8a8b59c13663f1f1d412ddc0d5775c92f/raise-1.1.1.tar.gz" } ] }