Skip to main content

Type-safe (bit)flags for python 3

Project description

build code quality code health coverage pypi github license: MIT

Quick Intro

With this module you can define type-safe (bit)flags. The style of the flag definition is very similar to the enum definitions you can create using the standard enum module of python 3.

Defining flags with the class syntax:

>>> from flags import Flags

>>> class TextStyle(Flags):
>>>     bold = 1            # value = 1 << 0
>>>     italic = 2          # value = 1 << 1
>>>     underline = 4       # value = 1 << 2

In most cases you just want to use the flags as a set (of bool variables) and the actual flag values aren’t important. To avoid manually setting unique flag values you can use auto assignment. To auto-assign a unique flag value use an empty iterable (for example empty tuple or list) as the value of the flag. Auto-assignment picks the first unused least significant bit for each auto-assignable flag in top-to-bottom order.

>>> class TextStyle(Flags):
>>>     bold = ()           # value = 1 << 0
>>>     italic = ()         # value = 1 << 1
>>>     underline = ()      # value = 1 << 2

As a shortcut you can call a flags class to create a subclass of it. This pattern has also been stolen from the standard enum module. The following flags definition is equivalent to the previous definition that uses the class syntax:

>>> TextStyle = Flags('TextStyle', 'bold italic underline')

Flags have human readable string representations and repr with more info:

>>> print(TextStyle.bold)
>>> print(repr(TextStyle.bold))
<TextStyle.bold bits=0x0001 data=None>

The type of a flag is the flags class it belongs to:

>>> type(TextStyle.bold)
<class '__main__.TextStyle'>
>>> isinstance(TextStyle.bold, TextStyle)

You can combine flags with bool operators. The result is also an instance of the flags class with the previously described properties.

>>> result = TextStyle.bold | TextStyle.italic
>>> print(result)
>>> print(repr(result))
<TextStyle(bold|italic) bits=0x0003>

Operators work in a type-safe way: you can combine only flags of the same type. Trying to combine them with instances of other types results in error:

>> result = TextStyle.bold | 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'TextStyle' and 'int'
>>> class OtherFlags(Flags):
...     flag0 = ()
>>> result = TextStyle.bold | OtherFlags.flag0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'TextStyle' and 'OtherFlags'

Flags and their combinations (basically the instances of the flags class) are immutable and hashable so they can be used as set members and dictionary keys:

>>> font_files = {}
>>> font_files[TextStyle.bold] = 'bold.ttf'
>>> font_files[TextStyle.italic] = 'italic.ttf'
>>> font_files == {TextStyle.bold: 'bold.ttf', TextStyle.italic: 'italic.ttf'}

The flags you define automatically have two “virtual” flags: no_flags and all_flags. no_flags is basically the zero flag and all_flags is the combination of all flags you’ve defined:

>>> TextStyle.no_flags
<TextStyle() bits=0x0000>
>>> TextStyle.all_flags
<TextStyle(bold|italic|underline) bits=0x0007>

Testing whether specific flags are set:

>>> result = TextStyle.bold | TextStyle.italic
>>> bool(result & TextStyle.bold)       # 1. oldschool bit twiddling
>>> TextStyle.bold in result            # 2. in operator
>>> result.bold                         # 3. attribute-style access

>From the above testing methods the attribute-style access can only check the presence of a single flag. With the & and in operators you can check the presence of multiple flags at the same time:

>>> bool((TextStyle.bold | TextStyle.italic) & TextStyle.all_flags)
>>> (TextStyle.bold | TextStyle.italic) in TextStyle.all_flags

If for some reason you need the actual integer value of the flags then you can cast them to int:

>>> int(TextStyle.bold)

You can convert the int() and str() representations of flags back into flags instances:

>>> TextStyle(2)
<TextStyle.italic bits=0x0002 data=None>
>>> TextStyle('TextStyle.bold')
<TextStyle.bold bits=0x0001 data=None>


pip install py-flags

Alternatively you can download the distribution from the following places:

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py-flags-1.0.1.tar.gz (21.7 kB view hashes)

Uploaded Source

Built Distribution

py_flags-1.0.1-py3-none-any.whl (13.0 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page