🗡️ Highlander Enum
"There can be only one!" - A Python library for mutually exclusive flag enums with smart conflict resolution.
Highlander Enum provides ExFlag and OptionsFlag - specialized variations of Python's IntFlag enum designed for scenarios where certain flags must be mutually exclusive. Think command-line options where --verbose and --quiet can't both be active, or configuration settings where only one mode can be selected at a time.
✨ Key Features
- 🚫 Mutually Exclusive Flags: Define groups where only one flag can be active
- 🔀 Smart Conflict Resolution: Choose how conflicts are handled (RHS wins, LHS wins, or strict mode)
- 🏃 Performance Optimized: Uses bitmasks for fast conflict detection during bitwise operations
- 📋 Command-Line Ready:
OptionsFlagincludes aliases and help text for CLI tools - 🎯 Type Safe: Full type hints and comprehensive test coverage (100%)
- 🐍 Modern Python: Supports Python 3.11, 3.12, and 3.13
🚀 Quick Start
Installation
pip install highlander-enum
Basic Usage
from highlander import ExFlag
class NetworkMode(ExFlag):
# Basic flags that can be combined
IPV4 = 1
IPV6 = 2
ENCRYPTION = 4
COMPRESSION = 8
# Mutually exclusive verbosity levels
QUIET = 16
VERBOSE = 32
DEBUG = 64, (QUIET, VERBOSE)
# RHS (right-hand side) wins by default
mode = NetworkMode.QUIET | NetworkMode.VERBOSE
print(mode) # NetworkMode.VERBOSE (VERBOSE wins)
# Non-conflicting flags combine normally
mode = NetworkMode.IPV4 | NetworkMode.ENCRYPTION | NetworkMode.VERBOSE
print(mode) # NetworkMode.ENCRYPTION|IPV4|VERBOSE
🎛️ Conflict Resolution Strategies
Choose how conflicts should be resolved when mutually exclusive flags are combined:
RHS (Right-Hand Side) - Default
class LogLevel(ExFlag): # Default: conflict="rhs"
ERROR = 1
WARN = 2
INFO = 4, (ERROR, WARN)
result = LogLevel.ERROR | LogLevel.INFO
print(result) # LogLevel.INFO (newer value wins)
LHS (Left-Hand Side)
class LogLevel(ExFlag, conflict="lhs"):
ERROR = 1
WARN = 2
INFO = 4, (ERROR, WARN)
result = LogLevel.ERROR | LogLevel.INFO
print(result) # LogLevel.ERROR (existing value wins)
Strict Mode
class LogLevel(ExFlag, conflict="strict"):
ERROR = 1
WARN = 2
INFO = 4, (ERROR, WARN)
try:
result = LogLevel.ERROR | LogLevel.INFO
except ValueError as e:
print(e) # LogLevel.INFO conflicts with LogLevel.ERROR
🖥️ Command-Line Options with OptionsFlag
Perfect for building CLI tools with rich help text and aliases:
from highlander import OptionsFlag
class ServerOptions(OptionsFlag):
# Format: VALUE, [aliases], "help text", [exclusions]
VERBOSE = 1, ["v", "verbose"], "Enable verbose logging"
QUIET = 2, ["q", "quiet"], "Suppress all output"
DEBUG = 4, ["d", "debug"], "Enable debug mode", (VERBOSE, QUIET)
# Different tuple formats supported
DAEMON = 8, "Run as daemon" # Just help text
CONFIG = 16, ["c", "config"], "Specify config file" # No exclusions
FORCE = 32, "Force operation", (DAEMON,) # Help + exclusions
# Access help text and aliases
opt = ServerOptions.VERBOSE
print(f"Help: {opt.help}") # Help: Enable verbose logging
print(f"Aliases: {opt.aliases}") # Aliases: ['v', 'verbose']
# Smart conflict resolution
flags = ServerOptions.QUIET | ServerOptions.DEBUG
print(flags) # ServerOptions.DEBUG (DEBUG wins over QUIET)
🔧 Advanced Usage
Dynamic Exclusions
Add exclusions at runtime:
class DynamicFlag(ExFlag):
A = 1
B = 2
C = 4
flag_a = DynamicFlag.A
flag_a.add_exclusions(DynamicFlag.B, DynamicFlag.C)
result = DynamicFlag.A | DynamicFlag.B
print(result) # DynamicFlag.A (conflicts resolved)
Multiple Exclusion Groups
Create complex relationships between different groups of flags:
class UITheme(ExFlag):
# Color schemes (mutually exclusive)
DARK = 1
LIGHT = 2
HIGH_CONTRAST = 4, (DARK, LIGHT)
# Size options (separate exclusion group)
SMALL = 8
MEDIUM = 16
LARGE = 32, (SMALL, MEDIUM)
# Independent options (no conflicts)
ANIMATIONS = 64
SOUND_EFFECTS = 128
# Mix and match from different groups
theme = UITheme.DARK | UITheme.LARGE | UITheme.ANIMATIONS
print(theme) # UITheme.ANIMATIONS|DARK|LARGE
# Conflicts within groups are resolved
theme = UITheme.DARK | UITheme.LIGHT | UITheme.SMALL
print(theme) # UITheme.LIGHT|SMALL (LIGHT wins over DARK)
Working with Integer Values
# Create flags from integer values with automatic conflict resolution
mixed_flags = NetworkMode(1 | 16 | 32) # IPV4 + QUIET + VERBOSE
print(mixed_flags) # NetworkMode.IPV4|QUIET (conflicts resolved)
# Check if flags are set
if NetworkMode.IPV4 in mixed_flags:
print("IPv4 is enabled")
🛡️ Type Safety & IDE Support
Highlander Enum provides full type hints for excellent IDE support:
from highlander import ExFlag
class StatusFlag(ExFlag):
IDLE = 1
BUSY = 2, (IDLE,)
ERROR = 4
def process_status(status: StatusFlag) -> str:
if status & StatusFlag.ERROR:
return "Error occurred"
elif status & StatusFlag.BUSY:
return "Currently busy"
else:
return "Ready"
# IDE will provide autocompletion and type checking
result = process_status(StatusFlag.BUSY | StatusFlag.ERROR)
print(result) # "Error occurred"
📊 Performance
Highlander Enum is designed for performance with bitwise operations:
import timeit
from highlander import ExFlag
class PerfTest(ExFlag):
A = 1
B = 2, (A,)
C = 4
D = 8
# Fast bitwise operations with conflict resolution
def test_operations():
return PerfTest.A | PerfTest.B | PerfTest.C
# Benchmark shows minimal overhead compared to standard IntFlag
print(f"Time per operation: {timeit.timeit(test_operations, number=100000):.6f}s")
🧪 Real-World Examples
File Processing Tool
from highlander import OptionsFlag
class FileProcessor(OptionsFlag):
# Output verbosity (mutually exclusive)
SILENT = 1, ["s", "silent"], "No output"
NORMAL = 2, ["n", "normal"], "Normal output"
VERBOSE = 4, ["v", "verbose"], "Verbose output", (SILENT, NORMAL)
# Processing modes (mutually exclusive)
FAST = 8, ["f", "fast"], "Fast processing"
ACCURATE = 16, ["a", "accurate"], "Accurate processing", (FAST,)
# Independent options
BACKUP = 32, ["b", "backup"], "Create backups"
COMPRESS = 64, ["c", "compress"], "Compress output"
def process_files(options: FileProcessor):
if options & FileProcessor.VERBOSE:
print("Verbose mode enabled")
if options & FileProcessor.BACKUP:
print("Creating backups")
# Usage
opts = FileProcessor.VERBOSE | FileProcessor.ACCURATE | FileProcessor.BACKUP
process_files(opts)
Game Settings
from highlander import ExFlag
class GraphicsSettings(ExFlag):
# Quality levels (mutually exclusive)
LOW = 1
MEDIUM = 2
HIGH = 4
ULTRA = 8, (LOW, MEDIUM, HIGH)
# Independent features
VSYNC = 16
HDR = 32
ANTIALIASING = 64
class GameConfig:
def __init__(self):
self.graphics = GraphicsSettings.MEDIUM | GraphicsSettings.VSYNC
def upgrade_quality(self):
# Automatically resolves conflicts
self.graphics |= GraphicsSettings.HIGH
def toggle_hdr(self):
self.graphics ^= GraphicsSettings.HDR
config = GameConfig()
print(config.graphics) # GraphicsSettings.VSYNC|MEDIUM
config.upgrade_quality()
print(config.graphics) # GraphicsSettings.VSYNC|HIGH (conflict resolved)
🏗️ Development
Requirements
- Python 3.11+
- uv (recommended) or pip
Setup
git clone https://github.com/florean/highlander-enum.git
cd highlander-enum
make install # Sets up virtual environment and pre-commit hooks
Testing
make test # Run pytest with coverage
make check # Run all quality checks (linting, type checking, etc.)
tox # Test across multiple Python versions
Building Documentation
make docs # Serve documentation locally
make docs-test # Test documentation build
📈 Project Roadmap
For 1.0
- New conflict resolutions: smallest wins and largest wins
- More robust constraint specification at member definition
- Better CLI integration for OptionsFlag - more helper methods or parser-specific subclasses
- Solidify internal API and naming
- More real-world usage
Future Enhancements
- Allow inheriting from and extending existing enums
🤝 Contributing
Contributions are welcome! This project maintains 100% test coverage because reliability is paramount. Please:
- Fork the repository
- Create a feature branch
- Add comprehensive tests for new functionality (we can help!)
- Ensure all tests pass and coverage remains 100%
- Submit a pull request
For bug reports, please open an issue. For feature requests or discussions about potential enhancements, start a discussion.
📄 License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
🔗 Links
- Documentation: https://florean.github.io/highlander-enum/
- Repository: https://github.com/florean/highlander-enum
- PyPI: https://pypi.org/project/highlander-enum/
"In the end, there can be only one... flag active in each subset of flags, unless you use add_exclusions and only apply it to one side, in which case yo—🗡️"
Metadata
Release files for highlander-enum 0.9.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| highlander_enum-0.9.1.tar.gz | 99.2 kB | Without provenance | Details for highlander_enum-0.9.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| highlander_enum-0.9.1-py3-none-any.whl | Python 3 | none | any | Details for highlander_enum-0.9.1-py3-none-any.whl |
Total release size: 118.8 kB
Release files / highlander_enum-0.9.1.tar.gz
| Download URL | highlander_enum-0.9.1.tar.gz |
|---|---|
| Size | 99.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
33d672ce0ccb231114cb67cb170b66bbc4542823a33f9a525ae62abf58b08e8e
|
|
BLAKE2b-256 checksum How to use checksums |
3e9f55e006ce29c589f10905ca3bfe7c8d7f51d2fc9f9763d1afdea35ea9282d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.6.14
|
Release files / highlander_enum-0.9.1-py3-none-any.whl
| Download URL | highlander_enum-0.9.1-py3-none-any.whl |
|---|---|
| Size | 19.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
53b355efa0f9884757ae1f6a90a3889873656d8e7c2e76abb8b942b97db276a9
|
|
BLAKE2b-256 checksum How to use checksums |
332c47adcb06723a75f952326c86e4f4229a627f95d6f23624816848f5dfc9ca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.6.14
|
Security for highlander-enum 0.9.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.