10.8. Enum Use Cases
10.8.1. SetUp
>>> from enum import Enum, IntEnum, StrEnum, Flag, IntFlag, auto
10.8.2. Use Case - 1
>>> class Color(Enum):
... AQUA = '#00FFFF'
... BLACK = '#000000'
... BLUE = '#0000ff'
... FUCHSIA = '#FF00FF'
... GRAY = '#808080'
... GREEN = '#008000'
... LIME = '#00ff00'
... MAROON = '#800000'
... NAVY = '#000080'
... OLIVE = '#808000'
... PINK = '#ff1a8c'
... PURPLE = '#800080'
... RED = '#ff0000'
... SILVER = '#C0C0C0'
... TEAL = '#008080'
... WHITE = '#ffffff'
... YELLOW = '#FFFF00'
10.8.3. Use Case - 2
>>> class Languages(Enum):
... EN = 'English'
... PL = 'Polish'
... DE = 'German'
10.8.4. Use Case - 3
>>> class Currency(Enum):
... PLN = 1
... USD = 4.00
... EUR = 4.20
10.8.5. Use Case - 4
>>> class CountryCode(Enum):
... PL = '+48'
... DE = '+49'
... US = '+1'
10.8.6. Use Case - 5
>>> class EmailType(Enum):
... PRIV = 1
... WORK = 2
10.8.7. Use Case - 6
>>> class PhoneType(Enum):
... HOME = 1
... WORK = 2
... ASSISTANT = 3
10.8.8. Use Case - 7
>>> class AddressType(Enum):
... BILLING = 1
... SHIPPING = 2
10.8.9. Use Case - 8
>>> class Gender(Enum):
... FEMALE = 1
... MALE = 2
... OTHER = 3
10.8.10. Use Case - 9
>>> class Settings(Enum):
... PROJECT_NAME = ...
... BASE_DIRECTORY = ...
... STATIC_ROOT = ...
10.8.11. Use Case - 10
>>> class ScreenResolution(Enum):
... X_MIN = 0
... X_MAX = 1920
... Y_MIN = 0
... Y_MAX = 1080
10.8.12. Use Case - 11
>>> class Polish(Enum):
... PLEASE = 'proszę'
... THANKS = 'dziękuję'
... SORRY = 'przepraszam'
>>> class English(Enum):
... PLEASE = 'please'
... THANKS = 'thank you'
... SORRY = 'I am sorry'
10.8.13. Use Case - 12
>>> class ScrumRole(Enum):
... PRODUCT_OWNER = 'po'
... SCRUM_MASTER = 'sm'
... TEAM_MEMBER = 'tm'
10.8.14. Use Case - 13
>>> class Permissions(Flag):
... READ = 0b100
... WRITE = 0b010
... EXECUTE = 0b001
10.8.15. Use Case - 14
>>> class IssueStatus(Enum):
... TODO = 'todo'
... IN_PROGRESS = 'in-progress'
... IN_REVIEW = 'in-review'
... IN_TEST = 'in-test'
... DONE = 'done'
... REJECTED = 'rejected'
10.8.16. Use Case - 15
Definitions:
>>> class ScrumRole(StrEnum):
... PRODUCT_OWNER = 'po'
... SCRUM_MASTER = 'sm'
... TEAM_MEMBER = 'tm'
>>>
>>>
>>> def assign(user, role):
... if not isinstance(role, ScrumRole):
... raise ValueError('Invalid role')
... user.role = role
>>>
>>>
>>> class User:
... pass
Usage:
>>> mark = User()
>>> mark.firstname = 'Mark'
>>> mark.lastname = 'Watney'
>>> assign(mark, ScrumRole.PRODUCT_OWNER)
>>>
>>> vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', 'role': <ScrumRole.PRODUCT_OWNER: 'po'>}
10.8.17. Use Case - 16
>>> Point = tuple[int,int]
>>>
>>> class Color(Enum):
... RED = '#FF0000'
... GREEN = '#00FF00'
... BLUE = '#0000FF'
>>> def draw_line(A: Point, B: Point, color: Color):
... if type(color) is not Color:
... possible = [str(c) for c in Color]
... raise TypeError(f'Invalid color, possible choices: {possible}')
... print(f'Drawing line from {A} to {B} with color {color.value}')
>>> draw_line(A=(0,0), B=(3,5), color=Color.RED)
Drawing line from (0, 0) to (3, 5) with color #FF0000
>>> draw_line(A=(0,0), B=(3,5), color='red')
Traceback (most recent call last):
TypeError: Invalid color, possible choices: ['Color.RED', 'Color.GREEN', 'Color.BLUE']
10.8.18. Use Case - 17
>>> from dataclasses import dataclass
>>>
>>>
>>> class Role(Enum):
... USER = 1
... STAFF = 2
... ADMIN = 3
>>>
>>>
>>> @dataclass
... class Account:
... firstname: str
... lastname: str
... role: Role
>>>
>>>
>>> mark = Account('Mark', 'Watney', role='not-existing')
>>> mark = Account('Mark', 'Watney', role=Role.USER)
10.8.19. Use Case - 18
r
- readw
- writex
- executerwx
- read, write, execute; 0b111 == 0o7rw-
- read, write; 0b110 == 0o6r-x
- read, execute; 0b101 == 0o5r--
- read only; 0b100 == 0o4rwxr-xr--
- user=(read,write,execute); group=(read,execute); others=(read)
>>> from enum import Enum
>>> from pathlib import Path
>>>
>>>
>>> class Permission(Enum):
... READ_WRITE_EXECUTE = 0b111
... READ_WRITE = 0b110
... READ_EXECUTE = 0b101
... READ = 0b100
... WRITE_EXECUTE = 0b011
... WRITE = 0b010
... EXECUTE = 0b001
... NONE = 0b000
>>>
>>>
>>> file = Path('/tmp/myfile.txt')
>>> file.touch()
>>> file.stat()
os.stat_result(st_mode=33188, st_ino=98480473, st_dev=16777220,
st_nlink=1, st_uid=501, st_gid=20, st_size=0,
st_atime=1624458230, st_mtime=1624458230,
st_ctime=1624458230)
>>>
>>> permissions = file.stat().st_mode
>>> decimal = int(permissions)
>>> octal = oct(permissions)
>>> binary = bin(permissions)
>>> print(f'{decimal=}, {octal=}, {binary}')
decimal=33188, octal='0o100644', 0b1000000110100100
>>>
>>> *_, user, group, others = oct(permissions)
>>> print(f'{user=} {group=} {others=}')
user='6' group='4' others='4'
>>>
>>> Permission(int(user))
<Permission.READ_WRITE: 6>
>>>
>>> Permission(int(group))
<Permission.READ: 4>
>>>
>>> Permission(int(others))
<Permission.READ: 4>
>>>
>>> file.unlink()
10.8.20. Use Case - 19
>>>
... from django.db import models
...
... class HttpMethod(models.TextChoices):
... GET = 'GET', _('GET')
... POST = 'POST', _('POST')
... PATCH = 'PATCH', _('PATCH')
... PUT = 'PUT', _('PUT')
... HEAD = 'HEAD', _('HEAD')
... DELETE = 'DELETE', _('DELETE')
... OPTIONS = 'OPTIONS', _('OPTIONS')
... TRACE = 'TRACE', _('TRACE')
... CONNECT = 'CONNECT', _('CONNECT')
...
...
... class Stage(models.TextChoices):
... PRODUCTION = 'production', _('Production')
... TEST = 'test', _('Test')
10.8.21. Use Case - 20
>>> class Planet(Enum):
... MERCURY = (3.303e+23, 2.4397e6)
... VENUS = (4.869e+24, 6.0518e6)
... EARTH = (5.976e+24, 6.37814e6)
... MARS = (6.421e+23, 3.3972e6)
... JUPITER = (1.9e+27, 7.1492e7)
... SATURN = (5.688e+26, 6.0268e7)
... URANUS = (8.686e+25, 2.5559e7)
... NEPTUNE = (1.024e+26, 2.4746e7)
...
... def __init__(self, mass, radius):
... self.mass = mass # in kilograms
... self.radius = radius # in meters
...
... @property
... def surface_gravity(self):
... # universal gravitational constant (m3 kg-1 s-2)
... G = 6.67300E-11
... return G * self.mass / (self.radius * self.radius)
>>> Planet.EARTH.value
(5.976e+24, 6378140.0)
>>>
>>> Planet.EARTH.surface_gravity
9.802652743337129
10.8.22. Use Case - 21
>>> Point = tuple[int,int]
>>>
>>> class Color(Enum):
... RED = '#FF0000'
... GREEN = '#00FF00'
... BLUE = '#0000FF'
>>> def draw_line(A: Point, B: Point, color: Color):
... if type(color) is not Color:
... possible = [str(c) for c in Color]
... raise TypeError(f'Invalid color, possible choices: {possible}')
... print(f'Drawing line from {A} to {B} with color {color.value}')
>>> draw_line(A=(0,0), B=(3,5), color=Color.RED)
Drawing line from (0, 0) to (3, 5) with color #FF0000
>>> draw_line(A=(0,0), B=(3,5), color='red')
Traceback (most recent call last):
TypeError: Invalid color, possible choices: ['Color.RED', 'Color.GREEN', 'Color.BLUE']
10.8.23. Use Case - 22
r
- readw
- writex
- executerwx
- read, write, execute; 0b111 == 0o7rw-
- read, write; 0b110 == 0o6r-x
- read, execute; 0b101 == 0o5r--
- read only; 0b100 == 0o4rwxr-xr--
- user=(read,write,execute); group=(read,execute); others=(read)
>>> from enum import Enum
>>> from pathlib import Path
>>>
>>>
>>> class Permission(Enum):
... READ_WRITE_EXECUTE = 0b111
... READ_WRITE = 0b110
... READ_EXECUTE = 0b101
... READ = 0b100
... WRITE_EXECUTE = 0b011
... WRITE = 0b010
... EXECUTE = 0b001
... NONE = 0b000
>>>
>>>
>>> file = Path('/tmp/myfile.txt')
>>> file.touch()
>>> file.stat()
os.stat_result(st_mode=33188, st_ino=98480473, st_dev=16777220,
st_nlink=1, st_uid=501, st_gid=20, st_size=0,
st_atime=1624458230, st_mtime=1624458230,
st_ctime=1624458230)
>>>
>>> permissions = file.stat().st_mode
>>> decimal = int(permissions)
>>> octal = oct(permissions)
>>> binary = bin(permissions)
>>> print(f'{decimal=}, {octal=}, {binary}')
decimal=33188, octal='0o100644', 0b1000000110100100
>>>
>>> *_, user, group, others = oct(permissions)
>>> print(f'{user=} {group=} {others=}')
user='6' group='4' others='4'
>>>
>>> Permission(int(user))
<Permission.READ_WRITE: 6>
>>>
>>> Permission(int(group))
<Permission.READ: 4>
>>>
>>> Permission(int(others))
<Permission.READ: 4>
>>>
>>> file.unlink()
10.8.24. Use Case - 23
>>> class IndexDrives(IntEnum):
... ControlWord = 0x6040
... StatusWord = 0x6041
... OperationMode = 0x6060
10.8.25. Use Case - 24
>>> from dataclasses import dataclass
>>>
>>>
>>> class Agency(Enum):
... NASA = auto()
... ESA = auto()
... JAXA = auto()
>>>
>>>
>>> @dataclass
... class Astronaut:
... firstname: str
... lastname: str
... agency: Agency
>>>
>>>
>>> mark = Astronaut('Mark', 'Watney', agency='not-existing')
>>> mark = Astronaut('Mark', 'Watney', agency=Agency.NASA)
10.8.26. Use Case - 25
>>>
... from django.db import models
...
... class HttpMethod(models.TextChoices):
... GET = 'GET', _('GET')
... POST = 'POST', _('POST')
... PATCH = 'PATCH', _('PATCH')
... PUT = 'PUT', _('PUT')
... HEAD = 'HEAD', _('HEAD')
... DELETE = 'DELETE', _('DELETE')
... OPTIONS = 'OPTIONS', _('OPTIONS')
... TRACE = 'TRACE', _('TRACE')
... CONNECT = 'CONNECT', _('CONNECT')
...
...
... class Stage(models.TextChoices):
... PRODUCTION = 'production', _('Production')
... TEST = 'test', _('Test')
10.8.27. Use Case - 26
>>> from enum import IntEnum
>>>
>>> class Permission(IntFlag):
... READ = 0b100
... WRITE = 0b010
... EXECUTE = 0b001
>>> file = Path('/tmp/myfile.txt')
>>> file.touch()
>>>
>>> file.stat()
os.stat_result(st_mode=33188, st_ino=22078540, st_dev=16777231, st_nlink=1, st_uid=501, st_gid=0, st_size=138, st_atime=1718195813, st_mtime=1718195769, st_ctime=1718195769)
>>>
>>> permissions = file.stat().st_mode
>>>
>>> permissions
33188
>>> oct(permissions)
'0o100644'
>>>
>>> *_, user, group, others = oct(permissions)
>>>
>>> Permission(int(user))
<Permission.READ|WRITE: 6>
>>>
>>> Permission(int(group))
<Permission.READ: 4>
>>>
>>> Permission(int(others))
<Permission.READ: 4>
10.8.28. Use Case - 27
Pattern Matching
Since Python 3.10: PEP 636 -- Structural Pattern Matching: Tutorial
Note, keycodes can vary depending on operating system and programming language used [mskeycodes], [jskeycodes].
>>> int('0x1B', base=16)
27
>>>
>>> hex(27)
'0x1b'
>>> class Key(Enum):
... ESC = 27 # 0x1B
... ARROW_LEFT = 37 # 0x25
... ARROW_UP = 38 # 0x26
... ARROW_RIGHT = 39 # 0x27
... ARROW_DOWN = 40 # 0x28
>>>
>>>
>>>
... match keyboard.on_key_press():
... case Key.ESC: game.quit()
... case Key.ARROW_LEFT: game.move_left()
... case Key.ARROW_UP: game.move_up()
... case Key.ARROW_RIGHT: game.move_right()
... case Key.ARROW_DOWN: game.move_down()
... case _: raise ValueError(f'Unrecognized key')
10.8.29. Use Case - 28
§6 pkt. 5 - Rozporządzenie Ministra Finansów z dnia 29 kwietnia 2019 r. w sprawie kas rejestrujących. Dziennik Ustaw - rok 2019 poz. 816
PTU - Podatek od Towarów i Usług (Services and Goods Tax)
>>> class PTU(Enum):
... A = 1.23 # VAT 23%
... B = 1.08 # VAT 8%
... C = 1.05 # VAT 5%
... D = 1.00 # VAT 0%
... E = None # VAT Exempt
>>>
>>> PLN = 1
>>> shopping_cart = [
... {'name': 'Bread', 'price': 3.99*PLN, 'ptu': PTU.C},
... {'name': 'Butter', 'price': 2.69*PLN, 'ptu': PTU.B},
... {'name': 'Ham', 'price': 5.99*PLN, 'ptu': PTU.A},
... {'name': 'Cheese', 'price': 4.19*PLN, 'ptu': PTU.B},
... ]
>>> total = sum(product['price'] * product['ptu'].value
... for product in shopping_cart)
>>> print(f'Total is: {total:.2f} PLN')
Total is: 18.99 PLN