Python's Enum with extra powers to play nice with labels and choices fields
Project description
============
Choices Enum
============
.. image:: https://img.shields.io/pypi/v/choicesenum.svg
:target: https://pypi-hypernode.com/pypi/choicesenum
.. image:: https://travis-ci.org/loggi/python-choicesenum.svg?branch=master
:target: https://travis-ci.org/loggi/python-choicesenum
.. image:: https://readthedocs.org/projects/python-choicesenum/badge/?version=latest
:target: https://python-choicesenum.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
Python's Enum with extra powers to play nice with labels and choices fields.
* Free software: BSD license
* Documentation: https://python-choicesenum.readthedocs.io.
------------
Installation
------------
Install ``choicesenum`` using pip::
$ pip install choicesenum
--------
Features
--------
* An ``ChoicesEnum`` that can be used to create constant groups.
* ``ChoicesEnum`` can define labels to be used in `choices` fields.
* Django fields included: ``EnumCharField`` and ``EnumIntegerField``.
* Support (tested) for Python 2.7, 3.4, 3.5 and 3.6.
* Support (tested) for Django 1.6.1 (with south), 1.7, 1.8, 1.9, 1.10, 1.11 and 2.0.
--------------
Usage examples
--------------
Example with ``HttpStatuses``:
.. code:: python
class HttpStatuses(ChoicesEnum):
OK = 200
BAD_REQUEST = 400
UNAUTHORIZED = 401
FORBIDDEN = 403
Example with ``Colors``:
.. code:: python
from choicesenum import ChoicesEnum
class Colors(ChoicesEnum):
RED = '#f00', 'Vermelho'
GREEN = '#0f0', 'Verde'
BLUE = '#00f', 'Azul'
Comparisson
-----------
All `Enum` types can be compared against their values:
.. code:: python
assert HttpStatuses.OK == 200
assert HttpStatuses.BAD_REQUEST == 400
assert HttpStatuses.UNAUTHORIZED == 401
assert HttpStatuses.FORBIDDEN == 403
status_code = HttpStatuses.OK
assert 200 <= status_code <= 300
assert Colors.RED == '#f00'
assert Colors.GREEN == '#0f0'
assert Colors.BLUE == '#00f'
Label for free
--------------
All `Enum` types have by default a `display` derived from the enum identifier:
.. code:: python
assert HttpStatuses.OK.display == 'Ok'
assert HttpStatuses.BAD_REQUEST.display == 'Bad request'
assert HttpStatuses.UNAUTHORIZED.display == 'Unauthorized'
assert HttpStatuses.FORBIDDEN.display == 'Forbidden'
You can easily define your own custom display for an `Enum` item using a tuple:
.. code:: python
class HttpStatuses(ChoicesEnum):
OK = 200, 'Everything is fine'
BAD_REQUEST = 400, 'You did a mistake'
UNAUTHORIZED = 401, 'I know your IP'
FORBIDDEN = 403
assert HttpStatuses.OK.display == 'Everything is fine'
assert HttpStatuses.BAD_REQUEST.display == 'You did a mistake'
assert HttpStatuses.UNAUTHORIZED.display == 'I know your IP'
assert HttpStatuses.FORBIDDEN.display == 'Forbidden'
Dynamic properties
------------------
For each enum item, a dynamic property ``is_<enum_item>`` is generated to allow
quick boolean checks:
.. code:: python
color = Colors.RED
assert color.is_red
assert not color.is_blue
assert not color.is_green
This feature is usefull to avoid comparing a received enum value against a know enum item.
For example, you can replace code like this:
.. code:: python
# status = HttpStatuses.BAD_REQUEST
def check_status(status):
if status == HttpStatuses.OK:
print("Ok!")
To this:
.. code:: python
def check_status(status):
if status.is_ok:
print("Ok!")
Custom methods and properties
-----------------------------
You can declare custom properties and methods:
.. code:: python
class HttpStatuses(ChoicesEnum):
OK = 200, 'Everything is fine'
BAD_REQUEST = 400, 'You did a mistake'
UNAUTHORIZED = 401, 'I know your IP'
FORBIDDEN = 403
@property
def is_error(self):
return self >= self.BAD_REQUEST
assert HttpStatuses.OK.is_error is False
assert HttpStatuses.BAD_REQUEST.is_error is True
assert HttpStatuses.UNAUTHORIZED.is_error is True
Iteration
---------
The enum type is iterable:
.. code:: python
>>> for color in Colors:
... print(repr(color))
Color('#f00').RED
Color('#0f0').GREEN
Color('#00f').BLUE
Order is guaranteed only for py3.4+. For fixed order in py2.7, you
can implement a magic attribute ``_order_``:
.. code:: python
from choicesenum import ChoicesEnum
class Colors(ChoicesEnum):
_order_ = 'RED GREEN BLUE'
RED = '#f00', 'Vermelho'
GREEN = '#0f0', 'Verde'
BLUE = '#00f', 'Azul'
Choices
-------
Use ``.choices()`` method to receive a list of tuples ``(item, display)``:
.. code:: python
assert list(Colors.choices()) == [
('#f00', 'Vermelho'),
('#0f0', 'Verde'),
('#00f', 'Azul'),
]
Values
-------
Use ``.values()`` method to receive a list of the inner values:
.. code:: python
assert Colors.values() == ['#f00', '#0f0', '#00f', ]
Options
-------
Even if a ``ChoicesEnum`` class is an iterator by itself, you can use ``.options()`` to convert the enum items to a list:
.. code:: python
assert Colors.options() == [Colors.RED, Colors.GREEN, Colors.BLUE]
Compatibility
-------------
The enum item can be used whenever the value is needed:
.. code:: python
assert u'Currrent color is {c} ({c.display})'.format(c=color) ==\
u'Currrent color is #f00 (Vermelho)'
Even in dicts and sets, as it shares the same `hash()` from his value:
.. code:: python
d = {
HttpStatuses.OK.value: "using value",
HttpStatuses.BAD_REQUEST: "using enum",
401: "from original value",
}
assert d[HttpStatuses.OK] == "using value"
assert d[HttpStatuses.BAD_REQUEST.value] == "using enum"
assert d[HttpStatuses.OK] == d[HttpStatuses.OK.value]
assert d[HttpStatuses.UNAUTHORIZED] == d[401]
There's also optimistic casting of inner types:
.. code:: python
assert int(HttpStatuses.OK) == 200
assert float(HttpStatuses.OK) == 200.0
assert str(HttpStatuses.BAD_REQUEST) == "400"
JSON
....
If you want json serialization, you have at least two options:
1. Patch the default serializer.
2. Write a custom JSONEncoder.
ChoicesEnum comes with a handy patch funtion, you need to add this
code to somewhere at the top of everything to automagically add
json serialization capabilities:
.. code:: python
from choicesenum.patches import patch_json
patch_json()
.. note::
Eventually ``__json__`` will be added to the stdlib, see
https://bugs.python.org/issue27362
------
Django
------
Fields
------
Usage with the custom Django fields:
.. code:: python
from django.db import models
from choicesenum.django.fields import EnumCharField
class ColorModel(models.Model):
color = EnumCharField(
max_length=100,
enum=Colors,
default=Colors.GREEN,
)
instance = ColorModel()
assert instance.color == Colors.GREEN
assert instance.color.is_green is True
assert instance.color.value == Colors.GREEN.value == '#0f0'
assert instance.color.display == Colors.GREEN.display
instance.color = '#f00'
assert instance.color == '#f00'
assert instance.color.value == '#f00'
assert instance.color.display == 'Vermelho'
Is guaranteed that the field value is *always* a `ChoicesEnum` item. Pay
attention that the field will only accept valid values for the ``Enum`` in use,
so if your field allow `null`, your enum should also:
.. code:: python
from django.db import models
from choicesenum import ChoicesEnum
from choicesenum.django.fields import EnumIntegerField
class UserStatus(ChoicesEnum):
UNDEFINED = None
PENDING = 1
ACTIVE = 2
INACTIVE = 3
DELETED = 4
class User(models.Model):
status = EnumIntegerField(enum=UserStatus, null=True, )
instance = User()
assert instance.status.is_undefined is True
assert instance.status.value is None
assert instance.status == UserStatus.UNDEFINED
assert instance.status.display == 'Undefined'
# again...
instance.status = None
assert instance.status.is_undefined is True
--------
Graphene
--------
Usage with Graphene_ Enums:
.. _Graphene: http://docs.graphene-python.org/en/latest/types/enums/#usage-with-python-enums
.. code:: python
UserStatusEnum = graphene.Enum.from_enum(UserStatus)
=======
History
=======
0.4.0 (2018-07-13)
------------------
* Optimistic casting of inner types (thanks @gabisurita).
* Optional stdlib patch to automagic json serialization support.
* Add Python3.7 to the test matrix.
0.3.0 (2018-06-22)
------------------
* Official Django 2.0 support (0.2.2 just works fine too).
* ``ChoicesEnum`` sharing the same hash() as his value. Can be used to retrieve/restore items in dicts (`d[enum] == d[enum.value]`).
0.2.2 (2017-12-01)
------------------
* Fix: Support queries through `select_related` with no `None` value defined (thanks @klette).
0.2.1 (2017-09-30)
------------------
* Fix South migrations for Django 1.6.
0.2.0 (2017-09-11)
------------------
* ``ChoicesEnum`` items are comparable by their values (==, !=, >, >=, <, <=) (thanks @jodal).
* +``ChoicesEnum.values``: Returns all the Enum's raw values (eq: ``[x.value for x in Enum]``).
0.1.7 (2017-09-10)
------------------
* Fix: ``ChoicesEnum`` is now hashable (thanks @jodal).
0.1.6 (2017-09-08)
------------------
* Fix: Proxy ``__len__`` calls to the inner enum value.
0.1.5 (2017-09-05)
------------------
* +ChoicesEnum.description: Alias for `label`, allow enum descriptors to be used by Graphene.
0.1.4 (2017-08-28)
------------------
* Fix South migrations for Django 1.6.
* ``ChoicesEnum`` repr can be used to reconstruct an instance (``item == eval(repr(item))``).
0.1.3 (2017-08-28)
------------------
* Fix sdist not including sub-modules (django contrib).
0.1.2 (2017-08-27)
------------------
* README fixes and improvements.
0.1.0 (2017-08-27)
------------------
* First release on PyPI.
Choices Enum
============
.. image:: https://img.shields.io/pypi/v/choicesenum.svg
:target: https://pypi-hypernode.com/pypi/choicesenum
.. image:: https://travis-ci.org/loggi/python-choicesenum.svg?branch=master
:target: https://travis-ci.org/loggi/python-choicesenum
.. image:: https://readthedocs.org/projects/python-choicesenum/badge/?version=latest
:target: https://python-choicesenum.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
Python's Enum with extra powers to play nice with labels and choices fields.
* Free software: BSD license
* Documentation: https://python-choicesenum.readthedocs.io.
------------
Installation
------------
Install ``choicesenum`` using pip::
$ pip install choicesenum
--------
Features
--------
* An ``ChoicesEnum`` that can be used to create constant groups.
* ``ChoicesEnum`` can define labels to be used in `choices` fields.
* Django fields included: ``EnumCharField`` and ``EnumIntegerField``.
* Support (tested) for Python 2.7, 3.4, 3.5 and 3.6.
* Support (tested) for Django 1.6.1 (with south), 1.7, 1.8, 1.9, 1.10, 1.11 and 2.0.
--------------
Usage examples
--------------
Example with ``HttpStatuses``:
.. code:: python
class HttpStatuses(ChoicesEnum):
OK = 200
BAD_REQUEST = 400
UNAUTHORIZED = 401
FORBIDDEN = 403
Example with ``Colors``:
.. code:: python
from choicesenum import ChoicesEnum
class Colors(ChoicesEnum):
RED = '#f00', 'Vermelho'
GREEN = '#0f0', 'Verde'
BLUE = '#00f', 'Azul'
Comparisson
-----------
All `Enum` types can be compared against their values:
.. code:: python
assert HttpStatuses.OK == 200
assert HttpStatuses.BAD_REQUEST == 400
assert HttpStatuses.UNAUTHORIZED == 401
assert HttpStatuses.FORBIDDEN == 403
status_code = HttpStatuses.OK
assert 200 <= status_code <= 300
assert Colors.RED == '#f00'
assert Colors.GREEN == '#0f0'
assert Colors.BLUE == '#00f'
Label for free
--------------
All `Enum` types have by default a `display` derived from the enum identifier:
.. code:: python
assert HttpStatuses.OK.display == 'Ok'
assert HttpStatuses.BAD_REQUEST.display == 'Bad request'
assert HttpStatuses.UNAUTHORIZED.display == 'Unauthorized'
assert HttpStatuses.FORBIDDEN.display == 'Forbidden'
You can easily define your own custom display for an `Enum` item using a tuple:
.. code:: python
class HttpStatuses(ChoicesEnum):
OK = 200, 'Everything is fine'
BAD_REQUEST = 400, 'You did a mistake'
UNAUTHORIZED = 401, 'I know your IP'
FORBIDDEN = 403
assert HttpStatuses.OK.display == 'Everything is fine'
assert HttpStatuses.BAD_REQUEST.display == 'You did a mistake'
assert HttpStatuses.UNAUTHORIZED.display == 'I know your IP'
assert HttpStatuses.FORBIDDEN.display == 'Forbidden'
Dynamic properties
------------------
For each enum item, a dynamic property ``is_<enum_item>`` is generated to allow
quick boolean checks:
.. code:: python
color = Colors.RED
assert color.is_red
assert not color.is_blue
assert not color.is_green
This feature is usefull to avoid comparing a received enum value against a know enum item.
For example, you can replace code like this:
.. code:: python
# status = HttpStatuses.BAD_REQUEST
def check_status(status):
if status == HttpStatuses.OK:
print("Ok!")
To this:
.. code:: python
def check_status(status):
if status.is_ok:
print("Ok!")
Custom methods and properties
-----------------------------
You can declare custom properties and methods:
.. code:: python
class HttpStatuses(ChoicesEnum):
OK = 200, 'Everything is fine'
BAD_REQUEST = 400, 'You did a mistake'
UNAUTHORIZED = 401, 'I know your IP'
FORBIDDEN = 403
@property
def is_error(self):
return self >= self.BAD_REQUEST
assert HttpStatuses.OK.is_error is False
assert HttpStatuses.BAD_REQUEST.is_error is True
assert HttpStatuses.UNAUTHORIZED.is_error is True
Iteration
---------
The enum type is iterable:
.. code:: python
>>> for color in Colors:
... print(repr(color))
Color('#f00').RED
Color('#0f0').GREEN
Color('#00f').BLUE
Order is guaranteed only for py3.4+. For fixed order in py2.7, you
can implement a magic attribute ``_order_``:
.. code:: python
from choicesenum import ChoicesEnum
class Colors(ChoicesEnum):
_order_ = 'RED GREEN BLUE'
RED = '#f00', 'Vermelho'
GREEN = '#0f0', 'Verde'
BLUE = '#00f', 'Azul'
Choices
-------
Use ``.choices()`` method to receive a list of tuples ``(item, display)``:
.. code:: python
assert list(Colors.choices()) == [
('#f00', 'Vermelho'),
('#0f0', 'Verde'),
('#00f', 'Azul'),
]
Values
-------
Use ``.values()`` method to receive a list of the inner values:
.. code:: python
assert Colors.values() == ['#f00', '#0f0', '#00f', ]
Options
-------
Even if a ``ChoicesEnum`` class is an iterator by itself, you can use ``.options()`` to convert the enum items to a list:
.. code:: python
assert Colors.options() == [Colors.RED, Colors.GREEN, Colors.BLUE]
Compatibility
-------------
The enum item can be used whenever the value is needed:
.. code:: python
assert u'Currrent color is {c} ({c.display})'.format(c=color) ==\
u'Currrent color is #f00 (Vermelho)'
Even in dicts and sets, as it shares the same `hash()` from his value:
.. code:: python
d = {
HttpStatuses.OK.value: "using value",
HttpStatuses.BAD_REQUEST: "using enum",
401: "from original value",
}
assert d[HttpStatuses.OK] == "using value"
assert d[HttpStatuses.BAD_REQUEST.value] == "using enum"
assert d[HttpStatuses.OK] == d[HttpStatuses.OK.value]
assert d[HttpStatuses.UNAUTHORIZED] == d[401]
There's also optimistic casting of inner types:
.. code:: python
assert int(HttpStatuses.OK) == 200
assert float(HttpStatuses.OK) == 200.0
assert str(HttpStatuses.BAD_REQUEST) == "400"
JSON
....
If you want json serialization, you have at least two options:
1. Patch the default serializer.
2. Write a custom JSONEncoder.
ChoicesEnum comes with a handy patch funtion, you need to add this
code to somewhere at the top of everything to automagically add
json serialization capabilities:
.. code:: python
from choicesenum.patches import patch_json
patch_json()
.. note::
Eventually ``__json__`` will be added to the stdlib, see
https://bugs.python.org/issue27362
------
Django
------
Fields
------
Usage with the custom Django fields:
.. code:: python
from django.db import models
from choicesenum.django.fields import EnumCharField
class ColorModel(models.Model):
color = EnumCharField(
max_length=100,
enum=Colors,
default=Colors.GREEN,
)
instance = ColorModel()
assert instance.color == Colors.GREEN
assert instance.color.is_green is True
assert instance.color.value == Colors.GREEN.value == '#0f0'
assert instance.color.display == Colors.GREEN.display
instance.color = '#f00'
assert instance.color == '#f00'
assert instance.color.value == '#f00'
assert instance.color.display == 'Vermelho'
Is guaranteed that the field value is *always* a `ChoicesEnum` item. Pay
attention that the field will only accept valid values for the ``Enum`` in use,
so if your field allow `null`, your enum should also:
.. code:: python
from django.db import models
from choicesenum import ChoicesEnum
from choicesenum.django.fields import EnumIntegerField
class UserStatus(ChoicesEnum):
UNDEFINED = None
PENDING = 1
ACTIVE = 2
INACTIVE = 3
DELETED = 4
class User(models.Model):
status = EnumIntegerField(enum=UserStatus, null=True, )
instance = User()
assert instance.status.is_undefined is True
assert instance.status.value is None
assert instance.status == UserStatus.UNDEFINED
assert instance.status.display == 'Undefined'
# again...
instance.status = None
assert instance.status.is_undefined is True
--------
Graphene
--------
Usage with Graphene_ Enums:
.. _Graphene: http://docs.graphene-python.org/en/latest/types/enums/#usage-with-python-enums
.. code:: python
UserStatusEnum = graphene.Enum.from_enum(UserStatus)
=======
History
=======
0.4.0 (2018-07-13)
------------------
* Optimistic casting of inner types (thanks @gabisurita).
* Optional stdlib patch to automagic json serialization support.
* Add Python3.7 to the test matrix.
0.3.0 (2018-06-22)
------------------
* Official Django 2.0 support (0.2.2 just works fine too).
* ``ChoicesEnum`` sharing the same hash() as his value. Can be used to retrieve/restore items in dicts (`d[enum] == d[enum.value]`).
0.2.2 (2017-12-01)
------------------
* Fix: Support queries through `select_related` with no `None` value defined (thanks @klette).
0.2.1 (2017-09-30)
------------------
* Fix South migrations for Django 1.6.
0.2.0 (2017-09-11)
------------------
* ``ChoicesEnum`` items are comparable by their values (==, !=, >, >=, <, <=) (thanks @jodal).
* +``ChoicesEnum.values``: Returns all the Enum's raw values (eq: ``[x.value for x in Enum]``).
0.1.7 (2017-09-10)
------------------
* Fix: ``ChoicesEnum`` is now hashable (thanks @jodal).
0.1.6 (2017-09-08)
------------------
* Fix: Proxy ``__len__`` calls to the inner enum value.
0.1.5 (2017-09-05)
------------------
* +ChoicesEnum.description: Alias for `label`, allow enum descriptors to be used by Graphene.
0.1.4 (2017-08-28)
------------------
* Fix South migrations for Django 1.6.
* ``ChoicesEnum`` repr can be used to reconstruct an instance (``item == eval(repr(item))``).
0.1.3 (2017-08-28)
------------------
* Fix sdist not including sub-modules (django contrib).
0.1.2 (2017-08-27)
------------------
* README fixes and improvements.
0.1.0 (2017-08-27)
------------------
* First release on PyPI.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
choicesenum-0.4.0.tar.gz
(25.5 kB
view details)
Built Distribution
File details
Details for the file choicesenum-0.4.0.tar.gz
.
File metadata
- Download URL: choicesenum-0.4.0.tar.gz
- Upload date:
- Size: 25.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f5bad4deaf51ccf6788f023164ec417f3bac4796845f4a0aa1579bd1489dd8ae |
|
MD5 | 42371ef9e144b84bbb3a3175a832b82b |
|
BLAKE2b-256 | 21145a5ea32818e705f03cbc41dc1fa65970696a93dfadf6977d4edec819c07a |
File details
Details for the file choicesenum-0.4.0-py2.py3-none-any.whl
.
File metadata
- Download URL: choicesenum-0.4.0-py2.py3-none-any.whl
- Upload date:
- Size: 9.0 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 46c0225dba9441ff73af56e545c59075282124f28549649bf4457ce155b984cc |
|
MD5 | a36f9d968b93deb2dd6e02adc318ca5a |
|
BLAKE2b-256 | 57f5fe8eec26b5bfa4c1e8be38928f42de0e5dcd5abcd4a07f7b40f2b33b2846 |