optional.py


Nameoptional.py JSON
Version 2.0.0 PyPI version JSON
download
home_pagehttps://github.com/Python-Optional/optional.py
SummaryAn implementation of the Optional object in Python
upload_time2024-03-13 22:36:42
maintainer
docs_urlNone
authorChad Befus
requires_python>=3.10,<4.0
licenseMIT
keywords optional datatype library
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Optional.py

[![Build Status](https://img.shields.io/pypi/v/optional.py.svg)](https://pypi.org/project/optional.py/)
[![test](https://github.com/Python-Optional/optional.py/actions/workflows/test.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/test.yaml)
[![lint](https://github.com/Python-Optional/optional.py/actions/workflows/lint.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/lint.yaml)
[![typecheck](https://github.com/Python-Optional/optional.py/actions/workflows/typecheck.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/typecheck.yaml)
[![format](https://github.com/Python-Optional/optional.py/actions/workflows/format.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/format.yaml)
[![editorconfig](https://github.com/Python-Optional/optional.py/actions/workflows/editorconfig.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/editorconfig.yaml)
[![License](https://img.shields.io/pypi/l/optional.py.svg)](https://pypi.org/project/optional.py/)
[![Python Versions](https://img.shields.io/pypi/pyversions/optional.py.svg)](https://pypi.org/project/optional.py/)
[![Contributors](https://img.shields.io/github/contributors/cbefus/optional.py.svg)](https://pypi.org/project/optional.py/)
[![Open Source Love](https://badges.frapsoft.com/os/v2/open-source.png?v=103)](https://github.com/open-source)
[![Downloads](https://pepy.tech/badge/optional-py)](https://pepy.tech/project/optional-py)

An Implementation of the Optional Object for Python

## Why

There is a difference between `None` as Empty and `None` as the result for an
Error. A common bad practice is to return `None` to indicate the absence of
something. Doing this introduces ambiguity into you code.

For example:

```python
thing = stuff.getSomeThing().getAnotherThing()
```

What will happen if the result from getSomeThing returns `None`? We will get an
`AttributeError: 'NoneType' object has no attribute 'getAnotherThing'`.

What can you do to prevent these kinds of exceptions? You can write defensively:

```python
something = stuff.getSomeThing()
if something is not None:
    thing = something.getAnotherThing()
```

However, if we add to our chain, you can imagine how the nesting of defensive
checks adds up quickly. These defensive checks obfuscate our actual business
logic, decreasing readability. Furthermore, defensive checking is an error prone
process, because it is easy to forget to check a required condition.

So we present you with an **Optional** object as an alternative.

## Install

**Compatible with Python 3.10 and up!**

```bash
pip install optional.py
```

## Usage

1. You can import it using:

   ```python
   from optional import Nothing, Option, Optional, Something
   ```

2. You can set it to empty:

   instead of: :scream_cat:

   ```python
   return None
   ```

   you can do: :smile_cat:

   ```python
   return Optional.empty()
   ```

   or

   ```python
   return Optional.of()
   ```

3. You can set it to have content:

   instead of: :scream_cat:

   ```python
   return "thing"
   ```

   you can do: :smile_cat:

   ```python
   return Optional.of("thing")
   ```

4. You can check if its present:

   instead of: :scream_cat:

   ```python
   if thing is not None:
   ```

   you can do: :smile_cat:

   ```python
   thing = some_func_returning_an_optional()
   if thing:
   ```

5. You can check if its empty:

   instead of: :scream_cat:

   ```python
   if thing is None:
   ```

   you can do: :smile_cat:

   ```python
   thing = some_func_returning_an_optional()
   if not thing:
   ```

6. You can match against the result and destructure the value:

   instead of: :scream_cat:

   ```python
   print(thing)
   ```

   you can do: :smirk_cat:

   ```python
   match some_func_returning_an_optional():
       case Something(thing):
           print(thing)
   ```

7. You can match against an empty optional, but **can't** destructure the value:

   instead of: :crying_cat_face:

   ```python
   if thing is None:
       print(None) # very odd
   ```

   you can do: :smirk_cat:

   ```python
   match some_func_returning_an_optional()
       case Nothing():
           print("We didn't get a thing!")
   ```

8. You can compare two optionals: :smile_cat:

   ```python
   Optional.empty() == Optional.empty() # True
   Optional.of("thing") == Optional.of("thing") # True
   Optional.of("thing") == Optional.empty() # False
   Optional.of("thing") == Optional.of("PANTS") # False
   ```

## Tests

There is complete test coverage and they pass in all Python versions 3.10 and up.

### Running Unit Tests

First, install `poetry` using the instructions located [here](https://python-poetry.org/docs/#installation).

Then, install the requirements using:

```bash
poetry install
```

You can run the tests (with coverage) using:

```bash
poetry run pytest
```


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Python-Optional/optional.py",
    "name": "optional.py",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.10,<4.0",
    "maintainer_email": "",
    "keywords": "optional datatype library",
    "author": "Chad Befus",
    "author_email": "crbefus@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/dc/cc/c14db2da7c2d643b4b0bb77ff6a957bcf86a63d7fbd15d268ecf089b76af/optional_py-2.0.0.tar.gz",
    "platform": null,
    "description": "# Optional.py\n\n[![Build Status](https://img.shields.io/pypi/v/optional.py.svg)](https://pypi.org/project/optional.py/)\n[![test](https://github.com/Python-Optional/optional.py/actions/workflows/test.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/test.yaml)\n[![lint](https://github.com/Python-Optional/optional.py/actions/workflows/lint.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/lint.yaml)\n[![typecheck](https://github.com/Python-Optional/optional.py/actions/workflows/typecheck.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/typecheck.yaml)\n[![format](https://github.com/Python-Optional/optional.py/actions/workflows/format.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/format.yaml)\n[![editorconfig](https://github.com/Python-Optional/optional.py/actions/workflows/editorconfig.yaml/badge.svg)](https://github.com/Python-Optional/optional.py/actions/workflows/editorconfig.yaml)\n[![License](https://img.shields.io/pypi/l/optional.py.svg)](https://pypi.org/project/optional.py/)\n[![Python Versions](https://img.shields.io/pypi/pyversions/optional.py.svg)](https://pypi.org/project/optional.py/)\n[![Contributors](https://img.shields.io/github/contributors/cbefus/optional.py.svg)](https://pypi.org/project/optional.py/)\n[![Open Source Love](https://badges.frapsoft.com/os/v2/open-source.png?v=103)](https://github.com/open-source)\n[![Downloads](https://pepy.tech/badge/optional-py)](https://pepy.tech/project/optional-py)\n\nAn Implementation of the Optional Object for Python\n\n## Why\n\nThere is a difference between `None` as Empty and `None` as the result for an\nError. A common bad practice is to return `None` to indicate the absence of\nsomething. Doing this introduces ambiguity into you code.\n\nFor example:\n\n```python\nthing = stuff.getSomeThing().getAnotherThing()\n```\n\nWhat will happen if the result from getSomeThing returns `None`? We will get an\n`AttributeError: 'NoneType' object has no attribute 'getAnotherThing'`.\n\nWhat can you do to prevent these kinds of exceptions? You can write defensively:\n\n```python\nsomething = stuff.getSomeThing()\nif something is not None:\n    thing = something.getAnotherThing()\n```\n\nHowever, if we add to our chain, you can imagine how the nesting of defensive\nchecks adds up quickly. These defensive checks obfuscate our actual business\nlogic, decreasing readability. Furthermore, defensive checking is an error prone\nprocess, because it is easy to forget to check a required condition.\n\nSo we present you with an **Optional** object as an alternative.\n\n## Install\n\n**Compatible with Python 3.10 and up!**\n\n```bash\npip install optional.py\n```\n\n## Usage\n\n1. You can import it using:\n\n   ```python\n   from optional import Nothing, Option, Optional, Something\n   ```\n\n2. You can set it to empty:\n\n   instead of: :scream_cat:\n\n   ```python\n   return None\n   ```\n\n   you can do: :smile_cat:\n\n   ```python\n   return Optional.empty()\n   ```\n\n   or\n\n   ```python\n   return Optional.of()\n   ```\n\n3. You can set it to have content:\n\n   instead of: :scream_cat:\n\n   ```python\n   return \"thing\"\n   ```\n\n   you can do: :smile_cat:\n\n   ```python\n   return Optional.of(\"thing\")\n   ```\n\n4. You can check if its present:\n\n   instead of: :scream_cat:\n\n   ```python\n   if thing is not None:\n   ```\n\n   you can do: :smile_cat:\n\n   ```python\n   thing = some_func_returning_an_optional()\n   if thing:\n   ```\n\n5. You can check if its empty:\n\n   instead of: :scream_cat:\n\n   ```python\n   if thing is None:\n   ```\n\n   you can do: :smile_cat:\n\n   ```python\n   thing = some_func_returning_an_optional()\n   if not thing:\n   ```\n\n6. You can match against the result and destructure the value:\n\n   instead of: :scream_cat:\n\n   ```python\n   print(thing)\n   ```\n\n   you can do: :smirk_cat:\n\n   ```python\n   match some_func_returning_an_optional():\n       case Something(thing):\n           print(thing)\n   ```\n\n7. You can match against an empty optional, but **can't** destructure the value:\n\n   instead of: :crying_cat_face:\n\n   ```python\n   if thing is None:\n       print(None) # very odd\n   ```\n\n   you can do: :smirk_cat:\n\n   ```python\n   match some_func_returning_an_optional()\n       case Nothing():\n           print(\"We didn't get a thing!\")\n   ```\n\n8. You can compare two optionals: :smile_cat:\n\n   ```python\n   Optional.empty() == Optional.empty() # True\n   Optional.of(\"thing\") == Optional.of(\"thing\") # True\n   Optional.of(\"thing\") == Optional.empty() # False\n   Optional.of(\"thing\") == Optional.of(\"PANTS\") # False\n   ```\n\n## Tests\n\nThere is complete test coverage and they pass in all Python versions 3.10 and up.\n\n### Running Unit Tests\n\nFirst, install `poetry` using the instructions located [here](https://python-poetry.org/docs/#installation).\n\nThen, install the requirements using:\n\n```bash\npoetry install\n```\n\nYou can run the tests (with coverage) using:\n\n```bash\npoetry run pytest\n```\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "An implementation of the Optional object in Python",
    "version": "2.0.0",
    "project_urls": {
        "Homepage": "https://github.com/Python-Optional/optional.py",
        "Repository": "https://github.com/Python-Optional/optional.py"
    },
    "split_keywords": [
        "optional",
        "datatype",
        "library"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9cb00f589f70c979bc12abf24a576caa5ed007d53b15a1737e23aad5aef482fb",
                "md5": "f6bdff8e26d30a024cc749ec669f04af",
                "sha256": "b79434effb80ff77a5c10c2f577a8618f7ea21d96587eb6b15bab32150a4a9bd"
            },
            "downloads": -1,
            "filename": "optional_py-2.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f6bdff8e26d30a024cc749ec669f04af",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10,<4.0",
            "size": 4921,
            "upload_time": "2024-03-13T22:36:41",
            "upload_time_iso_8601": "2024-03-13T22:36:41.003418Z",
            "url": "https://files.pythonhosted.org/packages/9c/b0/0f589f70c979bc12abf24a576caa5ed007d53b15a1737e23aad5aef482fb/optional_py-2.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "dcccc14db2da7c2d643b4b0bb77ff6a957bcf86a63d7fbd15d268ecf089b76af",
                "md5": "e8dce283a2d458c9fa150808e4173974",
                "sha256": "567f4cb8b80e14dd36693afa39c2897c82912abdfba3574212aed9353d4a7725"
            },
            "downloads": -1,
            "filename": "optional_py-2.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "e8dce283a2d458c9fa150808e4173974",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10,<4.0",
            "size": 3955,
            "upload_time": "2024-03-13T22:36:42",
            "upload_time_iso_8601": "2024-03-13T22:36:42.626375Z",
            "url": "https://files.pythonhosted.org/packages/dc/cc/c14db2da7c2d643b4b0bb77ff6a957bcf86a63d7fbd15d268ecf089b76af/optional_py-2.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-13 22:36:42",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Python-Optional",
    "github_project": "optional.py",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "optional.py"
}
        
Elapsed time: 0.21704s