Advanced Enumerations (compatible with Python's stdlib Enum), NamedTuples, and NamedConstants
76
Enhanced tuple implementation with named fields, default values, docstrings, and methods for creating structured data containers. The aenum NamedTuple provides more features than the standard library version.
Factory function for creating NamedTuple classes with named fields and optional features.
def NamedTuple(typename, fields, *,
rename=False, module=None, defaults=None,
size=TupleSize.fixed, kwds=False, **kwargs):
"""
Create a new NamedTuple class.
Args:
typename (str): Name of the new class
fields (str | list | dict): Field names or field definitions
rename (bool): Rename invalid field names automatically
module (str): Module name for the new class
defaults (list): Default values for fields
size (TupleSize): Size constraint (fixed, minimum, variable)
kwds (bool): Allow keyword-only arguments
**kwargs: Additional options
Returns:
type: New NamedTuple class with named fields
"""from aenum import NamedTuple
# Simple field names
Point = NamedTuple('Point', 'x y')
p = Point(10, 20)
print(p.x, p.y) # 10 20
# List of field names
Person = NamedTuple('Person', ['name', 'age', 'city'])
person = Person('Alice', 30, 'New York')
print(person.name) # Alice
# Field names from string
Book = NamedTuple('Book', 'title author isbn year')
book = Book('1984', 'George Orwell', '978-0451524935', 1949)from aenum import NamedTuple
# Using defaults parameter
Student = NamedTuple('Student', 'name grade school',
defaults=['A', 'Unknown School'])
s1 = Student('John')
print(s1.name, s1.grade, s1.school) # John A Unknown School
s2 = Student('Jane', 'B+', 'MIT')
print(s2.name, s2.grade, s2.school) # Jane B+ MIT
# Dictionary-style with defaults and docstrings
Employee = NamedTuple('Employee', {
'name': 'Employee full name',
'department': ('Engineering', 'Department name'), # (default, docstring)
'salary': (50000, 'Annual salary in USD'),
'remote': (False, 'Works remotely')
})
emp = Employee('Bob Smith')
print(emp.department) # Engineering
print(emp.salary) # 50000Define NamedTuple using class syntax with field definitions, methods, and properties.
class NamedTuple:
"""Base class for creating class-based NamedTuples."""
def _asdict(self):
"""Return contents as a dictionary."""
def _replace(self, **kwargs):
"""Return new instance with specified fields replaced."""
@classmethod
def _make(cls, iterable):
"""Create instance from iterable."""
@property
def _fields(self):
"""Tuple of field names."""from aenum import NamedTuple
class Point3D(NamedTuple):
x = 0, 'x coordinate', 0 # index, docstring, default
y = 1, 'y coordinate', 0
z = 2, 'z coordinate', 0
def distance_from_origin(self):
return (self.x**2 + self.y**2 + self.z**2)**0.5
def __str__(self):
return f'Point3D({self.x}, {self.y}, {self.z})'
# Usage
p1 = Point3D(3, 4, 5)
print(p1.distance_from_origin()) # 7.0710678118654755
print(p1) # Point3D(3, 4, 5)
# Default values
p2 = Point3D()
print(p2) # Point3D(0, 0, 0)
# Standard methods
print(p1._asdict()) # {'x': 3, 'y': 4, 'z': 5}
p3 = p1._replace(z=0)
print(p3) # Point3D(3, 4, 0)Enumeration defining size constraints for NamedTuples.
class TupleSize(Enum):
fixed = 'fixed' # Exact number of fields required
minimum = 'minimum' # At least this many fields required
variable = 'variable' # Variable number of fields allowedfrom aenum import NamedTuple, TupleSize
# Fixed size (default)
Point = NamedTuple('Point', 'x y', size=TupleSize.fixed)
# p = Point(1, 2, 3) # Would raise TypeError
# Minimum size
Args = NamedTuple('Args', 'command', size=TupleSize.minimum)
cmd1 = Args('ls')
cmd2 = Args('cp', 'file1', 'file2') # Extra args allowed
# Variable size
Data = NamedTuple('Data', 'header', size=TupleSize.variable)
data1 = Data('header')
data2 = Data('header', 'value1', 'value2', 'value3')from aenum import NamedTuple
# Detailed field definitions
User = NamedTuple('User', {
'username': (0, 'Unique username for login', None),
'email': (1, 'User email address', None),
'created_at': (2, 'Account creation timestamp', None),
'is_active': (3, 'Account active status', True),
'roles': (4, 'List of user roles', lambda: [])
})
# Access field information
print(User._field_defaults) # {'is_active': True, 'roles': <lambda>}
print(User._field_types) # {} (if no type hints)
# Create with partial information
user = User('alice', 'alice@example.com', '2023-01-01')
print(user.is_active) # True
print(user.roles) # []from aenum import NamedTuple
# Base tuple
Person = NamedTuple('Person', 'name age')
# Extend with additional fields
Employee = NamedTuple('Employee', Person._fields + ('department', 'salary'))
emp = Employee('John Doe', 30, 'Engineering', 75000)
print(emp.name) # John Doe
print(emp.department) # Engineering
# Class-based inheritance
class BaseRecord(NamedTuple):
id = 0, 'Record ID', None
created = 1, 'Creation timestamp', None
class UserRecord(BaseRecord):
username = 2, 'Username', None
email = 3, 'Email address', None
def __str__(self):
return f'User({self.username})'
user = UserRecord(1, '2023-01-01', 'alice', 'alice@example.com')
print(user) # User(alice)from aenum import NamedTuple
class Rectangle(NamedTuple):
width = 0, 'Rectangle width', 0
height = 1, 'Rectangle height', 0
@property
def area(self):
return self.width * self.height
@property
def perimeter(self):
return 2 * (self.width + self.height)
def scale(self, factor):
return Rectangle(self.width * factor, self.height * factor)
def is_square(self):
return self.width == self.height
rect = Rectangle(10, 5)
print(rect.area) # 50
print(rect.perimeter) # 30
print(rect.is_square()) # False
scaled = rect.scale(2)
print(scaled) # Rectangle(width=20, height=10)from aenum import NamedTuple
# Database configuration
DatabaseConfig = NamedTuple('DatabaseConfig', {
'host': ('localhost', 'Database host'),
'port': (5432, 'Database port'),
'database': (None, 'Database name'),
'username': (None, 'Database username'),
'password': (None, 'Database password'),
'pool_size': (10, 'Connection pool size'),
'timeout': (30, 'Connection timeout in seconds')
})
# Create configuration with defaults
db_config = DatabaseConfig(
database='myapp',
username='user',
password='secret'
)
print(db_config.host) # localhost
print(db_config.pool_size) # 10from aenum import NamedTuple
class APIResponse(NamedTuple):
status_code = 0, 'HTTP status code', 200
data = 1, 'Response data', None
headers = 2, 'Response headers', lambda: {}
timestamp = 3, 'Response timestamp', None
@property
def is_success(self):
return 200 <= self.status_code < 300
@property
def is_error(self):
return self.status_code >= 400
def get_header(self, name):
return self.headers.get(name.lower())
# Usage
response = APIResponse(
status_code=200,
data={'users': [{'id': 1, 'name': 'Alice'}]},
headers={'content-type': 'application/json'},
timestamp='2023-01-01T10:00:00Z'
)
print(response.is_success) # True
print(response.get_header('Content-Type')) # application/jsonfrom aenum import NamedTuple
class LogEntry(NamedTuple):
timestamp = 0, 'Log timestamp', None
level = 1, 'Log level', 'INFO'
message = 2, 'Log message', ''
module = 3, 'Source module', None
line_number = 4, 'Source line number', None
def __str__(self):
return f'[{self.timestamp}] {self.level}: {self.message}'
def with_context(self, **context):
"""Return new log entry with additional context."""
updated_message = f"{self.message} | Context: {context}"
return self._replace(message=updated_message)
# Create log entries
log1 = LogEntry('2023-01-01 10:00:00', 'ERROR', 'Database connection failed')
log2 = log1.with_context(database='postgres', host='localhost')
print(log1) # [2023-01-01 10:00:00] ERROR: Database connection failed
print(log2.message) # Database connection failed | Context: {'database': 'postgres', 'host': 'localhost'}from aenum import NamedTuple
from typing import Optional, List
from datetime import datetime
# Using with type hints (Python 3.6+)
class UserProfile(NamedTuple):
username: str = 0, 'Unique username', None
email: str = 1, 'Email address', None
full_name: Optional[str] = 2, 'Full display name', None
tags: List[str] = 3, 'User tags', lambda: []
created_at: datetime = 4, 'Creation timestamp', None
def display_name(self) -> str:
return self.full_name or self.username
# Usage maintains type safety
profile = UserProfile(
username='alice',
email='alice@example.com',
full_name='Alice Smith',
tags=['developer', 'python'],
created_at=datetime.now()
)
print(profile.display_name()) # Alice SmithAll NamedTuple instances provide these standard methods:
# Convert to dictionary
person_dict = person._asdict()
# Create new instance with some fields changed
updated_person = person._replace(age=31)
# Create from iterable
Person = NamedTuple('Person', 'name age city')
person_from_list = Person._make(['Bob', 25, 'Boston'])
# Field names and defaults
print(Person._fields) # ('name', 'age', 'city')
print(Person._field_defaults) # {}Install with Tessl CLI
npx tessl i tessl/pypi-aenumevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10