Skip to main content

🗡️ Highlander Enum

Release Build status codecov Commit activity License

"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: OptionsFlag includes 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:

  1. Fork the repository
  2. Create a feature branch
  3. Add comprehensive tests for new functionality (we can help!)
  4. Ensure all tests pass and coverage remains 100%
  5. 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.


"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)

Source distribution for highlander-enum 0.9.1
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)

Table of built distributions (wheels) for highlander-enum 0.9.1
File Interpreter ABI Platform Actions
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.

Release history Release notifications | RSS feed

This release

0.9.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page