Source code for flexicon.code.Lexicon.allomorph_collection
#
# allomorph_collection.py
#
# Class: AllomorphCollection
# Smart collection for allomorphs with type-aware filtering
# and unified access across multiple concrete types.
#
# Platform: Python.NET
# FieldWorks Version 9+
#
# Copyright 2025
#
"""
Smart collection class for allomorphs.
This module provides AllomorphCollection, a smart collection that manages
allomorphs while showing type diversity and supporting unified operations
across the two concrete types:
- MoStemAllomorph
- MoAffixAllomorph
Problem:
GetAll() returns objects with multiple concrete implementations. Users
need to:
- See which types are in the collection
- Filter by type if they want to
- Work with all types together without manual casting
- Filter by common properties that work across all types
Solution:
AllomorphCollection provides:
- __str__() showing type breakdown
- by_type() filtering to specific concrete types
- filter() for common criteria (form_contains, environment, type)
- Convenience methods (stem_allomorphs(), affix_allomorphs())
- Chainable filtering: allomorphs.stem_allomorphs().filter(form_contains='ing')
Example::
from flexlibs2.code.Lexicon.allomorph_collection import AllomorphCollection
# GetAll() now returns AllomorphCollection
allomorphs = allomorphOps.GetAll(entry)
print(allomorphs) # Shows type breakdown
# AllomorphCollection (8 total)
# MoStemAllomorph: 5 (62%)
# MoAffixAllomorph: 3 (38%)
# Filter by type
stems = allomorphs.stem_allomorphs()
print(len(stems)) # 5
# Filter by form
ing_allomorphs = allomorphs.filter(form_contains='ing')
# Chain filters
ing_stems = allomorphs.stem_allomorphs().filter(form_contains='ing')
# Iterate
for allomorph in allomorphs:
print(allomorph.form)
"""
from ..Shared.smart_collection import SmartCollection
from .allomorph import Allomorph
[docs]
class AllomorphCollection(SmartCollection):
"""
Smart collection for allomorphs with type-aware filtering.
Manages collections of allomorph (Allomorph wrapper objects) with
type-aware display and filtering capabilities. Supports filtering by
common properties (form, environment, type) and by concrete type.
Attributes:
_items: List of Allomorph wrapper objects
Example::
allomorphs = allomorphOps.GetAll(entry) # Returns AllomorphCollection
print(allomorphs) # Shows type breakdown
stems = allomorphs.stem_allomorphs() # Filter to MoStemAllomorph
ing = allomorphs.filter(form_contains='ing') # Form filter
both = allomorphs.stem_allomorphs().filter(form_contains='ing') # Chain
"""
def __init__(self, items=None):
"""
Initialize an AllomorphCollection.
Args:
items: Iterable of Allomorph objects, or None for empty.
Example::
collection = AllomorphCollection()
collection = AllomorphCollection([allomorph1, allomorph2, allomorph3])
"""
super().__init__(items)
[docs]
def filter(self, form_contains=None, environment=None, where=None):
"""
Filter the collection by common allomorph properties.
Supports filtering by properties that work across all allomorph types
(form, environment). For complex filtering, use where().
Args:
form_contains (str, optional): Filter to allomorphs whose form contains
this string (case-sensitive).
environment: Filter by environment object or GUID. Can be an IPhEnvironment
object or the environment GUID as string.
where (callable, optional): Custom predicate function. If provided,
other criteria are ignored.
Returns:
AllomorphCollection: New collection with filtered items.
Example::
# Filter by form
ing_allomorphs = allomorphs.filter(form_contains='ing')
# Filter by environment
env = project.lp.PhonologicalDataOA.EnvironmentsOS[0]
env_allomorphs = allomorphs.filter(environment=env)
# Custom filtering
long_forms = allomorphs.where(lambda a: len(a.form) > 3)
# Chain filters
ing_stems = allomorphs.filter(form_contains='ing').stem_allomorphs()
Notes:
- form_contains is case-sensitive
- All criteria are AND-ed together unless only one is provided
- where() takes precedence over other criteria
- Returns new collection (doesn't modify original)
- Use where() for complex custom filtering
"""
# If custom predicate provided, use it
if where is not None:
filtered = [item for item in self._items if where(item)]
return AllomorphCollection(filtered)
# Apply criteria filters
filtered = self._items
if form_contains is not None:
filtered = [allomorph for allomorph in filtered if form_contains in (allomorph.form or "")]
if environment is not None:
# Handle both object and GUID comparisons
environment_guid = None
if environment is not None:
if hasattr(environment, "Guid"):
environment_guid = str(environment.Guid)
else:
environment_guid = str(environment)
filtered = [
allomorph
for allomorph in filtered
if any(str(env.Guid) == environment_guid for env in allomorph.environment)
]
return AllomorphCollection(filtered)
[docs]
def where(self, predicate):
"""
Filter using a custom predicate function.
For filtering by complex criteria or properties not supported by filter().
Args:
predicate (callable): Function that takes an Allomorph and
returns True to include it in the result.
Returns:
AllomorphCollection: New collection with items matching the predicate.
Example::
# Complex predicate: allomorphs with form length > 3
long_forms = allomorphs.where(lambda a: len(a.form) > 3)
# Combining conditions
stem_with_env = allomorphs.where(
lambda a: a.is_stem_allomorph and len(a.environment) > 0
)
# Type checking combined with other criteria
affix_only = allomorphs.where(lambda a: a.is_affix_allomorph)
Notes:
- Predicate receives each Allomorph object
- Return True to include in result, False to exclude
- For simple filters (form, environment), use filter() instead
"""
filtered = [allomorph for allomorph in self._items if predicate(allomorph)]
return AllomorphCollection(filtered)
[docs]
def stem_allomorphs(self):
"""
Get only the stem allomorphs from the collection.
Convenience method for filtering to MoStemAllomorph objects only.
Returns:
AllomorphCollection: New collection with only MoStemAllomorph objects.
Example::
stems = allomorphs.stem_allomorphs()
print(f"Found {len(stems)} stem allomorphs")
# Chain with other filters
ing_stems = allomorphs.stem_allomorphs().filter(form_contains='ing')
Notes:
- Equivalent to by_type('MoStemAllomorph')
- Stem allomorphs are variants of stems/roots
- Use is_stem_allomorph on individual allomorphs to check type
"""
return self.by_type("MoStemAllomorph")
[docs]
def affix_allomorphs(self):
"""
Get only the affix allomorphs from the collection.
Convenience method for filtering to MoAffixAllomorph objects only.
Returns:
AllomorphCollection: New collection with only MoAffixAllomorph objects.
Example::
affixes = allomorphs.affix_allomorphs()
print(f"Found {len(affixes)} affix allomorphs")
# Chain with other filters
ing_affixes = allomorphs.affix_allomorphs().filter(form_contains='ing')
Notes:
- Equivalent to by_type('MoAffixAllomorph')
- Affix allomorphs are variants of prefixes, suffixes, infixes, etc.
- Use is_affix_allomorph on individual allomorphs to check type
"""
return self.by_type("MoAffixAllomorph")
def __repr__(self):
"""Technical representation."""
return f"AllomorphCollection({len(self._items)} allomorphs)"