Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/python-optional/optional.py
An Implementation of the Optional Object for Python
https://github.com/python-optional/optional.py
clean-code optionals python python27 python3
Last synced: about 1 month ago
JSON representation
An Implementation of the Optional Object for Python
- Host: GitHub
- URL: https://github.com/python-optional/optional.py
- Owner: Python-Optional
- License: mit
- Created: 2018-08-16T23:47:19.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2024-04-18T23:45:13.000Z (7 months ago)
- Last Synced: 2024-04-19T16:16:07.014Z (7 months ago)
- Topics: clean-code, optionals, python, python27, python3
- Language: Python
- Size: 209 KB
- Stars: 43
- Watchers: 3
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 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
```