flexicon.code.Shared package¶
Submodules¶
flexicon.code.Shared.FilterOperations module¶
- class flexicon.code.Shared.FilterOperations.FilterTypes[source]¶
Bases:
objectFilter type constants for different object classes.
- LEXENTRY = 'LexEntry'¶
- WORDFORM = 'Wordform'¶
- TEXT = 'Text'¶
- SENSE = 'Sense'¶
- ALLOMORPH = 'Allomorph'¶
- CUSTOM = 'Custom'¶
- class flexicon.code.Shared.FilterOperations.FilterOperations(project)[source]¶
Bases:
objectThis class provides operations for managing saved filters and queries in a FieldWorks project.
Filters allow you to define reusable criteria for selecting and filtering different types of objects (entries, wordforms, texts, etc.). Each filter has a name, type, and criteria definition that can be applied to collections of objects.
This class should be accessed via FLExProject.Filter property.
Usage:
from flexlibs2 import FLExProject project = FLExProject() project.OpenProject("my project", writeEnabled=True) # Create a new filter filter_obj = project.Filter.Create( "Verbs", FilterTypes.LEXENTRY, {"pos": "verb"} ) # Get all filters for f in project.Filter.GetAll(): name = project.Filter.GetName(f) print(name) # Find a filter by name filter_obj = project.Filter.Find("Verbs") # Apply filter to entries entries = list(project.LexEntry.GetAll()) matching = project.Filter.ApplyFilter(filter_obj, entries) # Export filter definition project.Filter.ExportFilter(filter_obj, "/path/to/filter.json") project.CloseProject()
Notes
Filters are stored as custom data structures in the project
Filter criteria are stored as JSON-serializable dictionaries
Different filter types support different criteria
Filters can be exported and imported for reuse across projects
- GetAll(**kwargs)¶
- Create(*args, **kwargs)¶
Automatically instantiate and call the method.
- Delete(*args, **kwargs)¶
Automatically instantiate and call the method.
- Find(*args, **kwargs)¶
Automatically instantiate and call the method.
- Exists(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetName(*args, **kwargs)¶
Automatically instantiate and call the method.
- SetName(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetCriteria(*args, **kwargs)¶
Automatically instantiate and call the method.
- SetCriteria(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetFilterType(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetGuid(*args, **kwargs)¶
Automatically instantiate and call the method.
- ApplyFilter(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetMatchCount(*args, **kwargs)¶
Automatically instantiate and call the method.
- ExportFilter(*args, **kwargs)¶
Automatically instantiate and call the method.
- ImportFilter(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetFiltersByType(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetDateCreated(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetDateModified(*args, **kwargs)¶
Automatically instantiate and call the method.
- Duplicate(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetSyncableProperties(*args, **kwargs)¶
Automatically instantiate and call the method.
- CompareTo(*args, **kwargs)¶
Automatically instantiate and call the method.
flexicon.code.Shared.MediaOperations module¶
- class flexicon.code.Shared.MediaOperations.MediaType[source]¶
Bases:
objectMedia file type constants.
- UNKNOWN = 0¶
- AUDIO = 1¶
- VIDEO = 2¶
- IMAGE = 3¶
- class flexicon.code.Shared.MediaOperations.MediaOperations(project)[source]¶
Bases:
BaseOperationsProvides operations for managing media files in a FLEx project.
Media files include audio recordings, videos, and images that can be attached to lexical entries, pronunciations, examples, and other objects. This class handles both the database references (ICmFile) and file system operations for project media.
This class should be accessed via FLExProject.Media property.
Example
>>> project = FLExProject() >>> project.OpenProject("MyProject", writeEnabled=True) >>> # Get all media files >>> for media in project.Media.GetAll(): ... path = project.Media.GetInternalPath(media) ... print(path) >>> # Add a new media file >>> media = project.Media.Create("/path/to/audio.wav") >>> # Check media type >>> if project.Media.IsAudio(media): ... print("This is an audio file") >>> project.CloseProject()
- GetAll(**kwargs)¶
- Create(*args, **kwargs)¶
Automatically instantiate and call the method.
- Delete(*args, **kwargs)¶
Automatically instantiate and call the method.
- Duplicate(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetSyncableProperties(*args, **kwargs)¶
Automatically instantiate and call the method.
- CompareTo(*args, **kwargs)¶
Automatically instantiate and call the method.
- Find(*args, **kwargs)¶
Automatically instantiate and call the method.
- Exists(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetInternalPath(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetExternalPath(*args, **kwargs)¶
Automatically instantiate and call the method.
- SetInternalPath(*args, **kwargs)¶
Automatically instantiate and call the method.
- RenameMediaFile(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetLabel(*args, **kwargs)¶
Automatically instantiate and call the method.
- SetLabel(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetMediaType(*args, **kwargs)¶
Automatically instantiate and call the method.
- IsAudio(*args, **kwargs)¶
Automatically instantiate and call the method.
- IsVideo(*args, **kwargs)¶
Automatically instantiate and call the method.
- IsImage(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetOwners(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetOwnerCount(*args, **kwargs)¶
Automatically instantiate and call the method.
- CopyToProject(*args, **kwargs)¶
Automatically instantiate and call the method.
- IsValid(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetGuid(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetHvo(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetFileSize(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetAllByType(*args, **kwargs)¶
Automatically instantiate and call the method.
- GetOrphanedMedia(*args, **kwargs)¶
Automatically instantiate and call the method.
flexicon.code.Shared.catalog module¶
- class flexicon.code.Shared.catalog.CatalogEntry(id: str, guid: str, abbrev: ~typing.Dict[str, str] = <factory>, term: ~typing.Dict[str, str] = <factory>, def_: ~typing.Dict[str, str] = <factory>, children: ~typing.List[~flexicon.code.Shared.catalog.CatalogEntry] = <factory>)[source]¶
Bases:
objectOne <item type=”category”> from the GOLDEtic catalog.
- Variables:
id (str) – The catalog id, e.g. “Adjective”. This is the suffix of the canonical CatalogSourceId (“GOLD:Adjective”).
guid (str) – The canonical FW GUID for this category, as a string. e.g. “30d07580-5052-4d91-bc24-469b8b2d7df9”.
abbrev (Dict[str, str]) – Map of writing-system tag -> abbreviation string, e.g. {“en”: “adj”, “fr”: “adj”, “ko”: “형”}.
term (Dict[str, str]) – Map of writing-system tag -> name/term string, e.g. {“en”: “Adjective”, “fr”: “Adjectif”}.
def (Dict[str, str]) – Map of writing-system tag -> definition string. Note the trailing underscore: “def” is a Python keyword.
children (List[flexicon.code.Shared.catalog.CatalogEntry]) – List of nested CatalogEntry items (sub-categories in the catalog hierarchy).
- id: str¶
- guid: str¶
- abbrev: Dict[str, str]¶
- term: Dict[str, str]¶
- def_: Dict[str, str]¶
- children: List[CatalogEntry]¶
- class flexicon.code.Shared.catalog.CatalogImportResult(created_count: int = 0, skipped_count: int = 0, created_guids: ~typing.List[str] = <factory>, warnings: ~typing.List[str] = <factory>)[source]¶
Bases:
objectSummary of what happened during a catalog import.
- Variables:
created_count (int) – Number of new POSs created.
skipped_count (int) – Number of catalog entries skipped because a POS with the same canonical GUID already exists.
created_guids (List[str]) – Canonical GUIDs (as strings) for the POSs that were created. Useful for verification and tests.
warnings (List[str]) – Human-readable warnings (e.g. WS tags present in the catalog but missing from the project).
- created_count: int = 0¶
- skipped_count: int = 0¶
- created_guids: List[str]¶
- warnings: List[str]¶
- flexicon.code.Shared.catalog.find_catalog_file(filename, subdir='Templates')[source]¶
Locate a catalog XML file under the FieldWorks install.
Uses FLExGlobals.FWCodeDir (resolved during FLEx init from the Windows registry) so it works against whatever FW install the user actually has. Does not hard-code “C:/Program Files/SIL/…”.
- Parameters:
filename (str) – The catalog filename, e.g. “GOLDEtic.xml”.
subdir (str) – Relative subdirectory under FWCodeDir; default “Templates” (used for GOLDEtic.xml). For MGA gloss lists, pass “Language Explorer/MGA/GlossLists”. Forward slashes are converted to OS-native separators by os.path.join.
- Returns:
Absolute path to the catalog file.
- Return type:
str
- Raises:
RuntimeError – If FLExGlobals.FWCodeDir has not been initialised (caller must have imported flexlibs2 first).
FileNotFoundError – If the file does not exist at the expected path.
- flexicon.code.Shared.catalog.parse_etic_catalog(path)[source]¶
Parse a GOLDEtic-shaped POS catalog XML file into a tree of CatalogEntry objects.
- Parameters:
path (str) – Absolute path to GOLDEtic.xml.
- Returns:
The top-level catalog entries. Nested sub-categories are reachable via each entry’s .children.
- Return type:
list[CatalogEntry]
Notes
The root element is <eticPOSList>; we walk its direct <item type=”category”> children and recurse from there.
Other root shapes are not supported by this function.
- flexicon.code.Shared.catalog.parse_etic_gloss_list(path)[source]¶
Parse a PhonFeatsEticGlossList-shaped catalog (root <eticGlossList>) into a flat list of feature CatalogEntry objects.
- Items have type=”group” | “fsType” | “feature” | “value”:
“group” entries are organizational only (not representable in LCM). They are skipped at every level, but the parser recurses INTO them so any features they contain still get returned.
“fsType” entries are agreement-category containers (e.g.
tCommonAgrholds the Bantu number featuresfBantuSg,fBantuPl,fBantuMany). Like “group” they are organizational and are not themselves CatalogEntry items, but the parser recurses INTO them so the features they hold get returned. (issue #192)“feature” entries become CatalogEntry items in the returned list. Each feature’s value children are attached to its .children list.
“value” entries become CatalogEntry children of their parent feature entry.
- Parameters:
path (str) – Absolute path to e.g. PhonFeatsEticGlossList.xml.
- Returns:
Flat list of feature entries with their value entries attached as .children. Group structure is flattened away.
- Return type:
list[CatalogEntry]
- Raises:
ValueError – If the root element is not <eticGlossList>.
- class flexicon.code.Shared.catalog.SegmentDefinition(code_point_id: str, representation: str, descriptions: ~typing.Dict[str, str] = <factory>, feature_pairs: ~typing.List[tuple] = <factory>)[source]¶
Bases:
objectOne <SegmentDefinition> from the BasicIPAInfo.xml catalog.
BasicIPAInfo.xml ships with FW under Templates/BasicIPAInfo.xml. Unlike GOLDEtic / eticGlossList catalogs, segments have NO per-entry GUIDs: the only stable identifier is
code_point_id(e.g. “u0061”), which the importer uses to dedup within a single pass but cannot use for cross-import idempotency.- Variables:
code_point_id (str) – Value of the
unicodeCodePointsattribute on the (first)<Representation>element, e.g."u0061"for the segment “a”.representation (str) – The element text of the (first)
<Representation>, e.g."a". This is what the importer writes intoIPhPhoneme.NameandBasicIPASymbol.descriptions (Dict[str, str]) – Map of
langattribute -> description text, e.g.{"en": "Open front unrounded vowel"}.feature_pairs (List[tuple]) – List of
(feature_id, value_id)tuples from the<Features>/<FeatureValuePair>children. Both ids reference PhonFeats catalog entries (e.g.("fPAConsonantal", "vPAConsonantalNegative")). Empty list when the segment has<Features/>.
- code_point_id: str¶
- representation: str¶
- descriptions: Dict[str, str]¶
- feature_pairs: List[tuple]¶
- flexicon.code.Shared.catalog.parse_basic_ipa_info(path)[source]¶
Parse a BasicIPAInfo.xml-shaped segment catalog (root
<SegmentDefinitions>) into a flat list of SegmentDefinition objects.- Parameters:
path (str) – Absolute path to BasicIPAInfo.xml.
- Returns:
One entry per
<SegmentDefinition>. Order in the returned list matches order in the source file (FW ships the catalog with a meaningful order: tones first, then vowels and consonants).- Return type:
list[SegmentDefinition]
- Raises:
ValueError – If the root element is not
<SegmentDefinitions>.
Notes
Only the FIRST
<Representation>child is captured. The stock catalog has exactly one per segment; multi-representation segments would need a richer dataclass.Description
langtags use the lowercase short form (“en”, “es”, “fr”, …). The catalog ships English plus partial Spanish; other languages may be sparse.Segments with empty
<Features/>(the tone entries at the head of the file) end up withfeature_pairs == [].
- flexicon.code.Shared.catalog.find_catalog_entry(entries, source_id)[source]¶
Walk a list of CatalogEntry trees (depth-first) and return the entry whose id matches source_id. Known catalog prefixes (“GOLD:”, “PHON:”) are stripped before comparison so both “GOLD:Adjective” and “Adjective” work.
- Parameters:
entries (list[CatalogEntry]) – Result of parse_etic_catalog() or parse_etic_gloss_list().
source_id (str) – Catalog source id, with or without a known prefix.
- Returns:
The matching entry, or None if no match.
- Return type:
CatalogEntry or None
- flexicon.code.Shared.catalog.count_catalog_entries(entries)[source]¶
Count all CatalogEntry items in a forest, including nested children.
Convenience helper for tests / smoke checks. GOLDEtic.xml has 16 top-level entries and 58 entries total.
- Parameters:
entries (list[CatalogEntry]) – Result of parse_etic_catalog().
- Returns:
Total number of entries across the tree.
- Return type:
int
flexicon.code.Shared.catalog_backed module¶
- class flexicon.code.Shared.catalog_backed.CatalogBackedMixin[source]¶
Bases:
objectMixin for Operations classes that wrap LCM possibility-list / feature-system domains backed by a SIL catalog XML file (GOLDEtic, PhonFeatsEticGlossList, etc.).
Subclasses declare class-level constants:
- CATALOG_FILE
Filename of the catalog XML, e.g. “GOLDEtic.xml” or “PhonFeatsEticGlossList.xml”.
- CATALOG_SUBDIR
Relative subdirectory under FWCodeDir. Defaults to “Templates” in this base; subclasses override for catalogs that live elsewhere (e.g. “Language Explorer/MGA/GlossLists”).
- CATALOG_PARSER
Staticmethod returning
list[CatalogEntry]from a file path. Eitherparse_etic_catalogorparse_etic_gloss_list.- CATALOG_PREFIX_WRITE
Either a string (e.g.
"GOLD") orNone.String: the mixin writes
CatalogSourceId = "{PREFIX}:{entry.id}".None: the mixin writes
CatalogSourceId = entry.id(the bare FW convention used by PhonFeats).
- DOMAIN_LABEL
Short human-readable label used in error messages, e.g. “POS” or “feature”.
Subclasses must also set the optional class flag:
- _supports_recursive_entries (bool, default False)
True for catalogs whose CatalogEntry tree is hierarchical and should produce a parallel hierarchy of LCM objects (POS: top-level entries become top-level POSs, nested entries become SubPossibilitiesOS). When True, the mixin recurses on entry.children calling _create_from_entry(child, parent_obj=created_obj).
False for catalogs whose top-level entries own a flat list of children that need bespoke per-domain handling (PhonFeats: value children of a feature). When False, the mixin invokes
_handle_entry_children(entry, created_obj, ...)once per top-level entry; the subclass is responsible for the children.
Subclasses implement these hook methods:
- _factory_create_attached(self, guid, parent)
Try the LCM 2-arg factory overload
Create(Guid, parent).parentis whatever was passed to_create_from_entry- either the parent LCM object (subcategory case) or the “root list” returned by_get_root_list()(top-level case). Must return either the new LCM object (Path A success) orNone(Path A failed; mixin then runs Path B).- _path_b_attach(self, new_obj, parent_obj)
Path B fallback: attach
new_obj(just created viaconcrete_factory.Create(guid)) to its owning collection.parent_objmatches theparentarg passed to the top-level _create_from_entry call; if it is None and the domain supports subcategories, the subclass attaches to the top-level collection on_get_root_list().POS:
parent_obj.SubPossibilitiesOS.Add(new_obj)if parent_obj is a POS, elseself.project.lp.PartsOfSpeechOA.PossibilitiesOS.Add(new_obj).PhonFeats:
self._get_root_list().FeaturesOC.Add(new_obj).
- _cast_to_domain(self, raw_lcm_obj)
Return the interface-cast view of the raw LCM object.
POS:
IPartOfSpeech(raw)PhonFeats:
IFsClosedFeature(raw)
- _set_localized(self, obj, term, abbrev,
def_, missing_ws_seen, warnings) Per-domain multistring writes.
term,abbrevanddef_are{ws_tag: text}dicts from the CatalogEntry. The subclass writesobj.Name/obj.Abbreviation/obj.Description(where present) using_set_multistringwhich the mixin provides.- _walk_existing(self)
Yield existing items for idempotency lookup. For domains with subcategories (POS), this walks recursively. For flat domains (PhonFeats), it yields top-level items.
- _get_root_list(self)
Return the top-level owner object. POS returns
self.project.lp.PartsOfSpeechOA; PhonFeats returnsself.project.lp.PhFeatureSystemOA.- _handle_entry_children(self, entry, created_obj, missing_ws_seen, warnings, result)
Per-domain handling of CatalogEntry.children.
POS: empty (use
_supports_recursive_entries=Trueinstead).PhonFeats: walk
entry.children(value entries) and create IFsSymFeatVal items undercreated_obj.ValuesOC, respecting per-feature value-GUID idempotency.
resultis the CatalogImportResult (so per-value created/skipped counts and created_guids can be updated).resultis None when called from CreateFromCatalog or FixGuidsAgainstCatalog; subclasses must handle that.
The mixin provides three public methods (ImportCatalog, CreateFromCatalog, FixGuidsAgainstCatalog) plus private helpers (_create_from_entry, _get_all_guids, _find_by_guid, _set_multistring, _flattened_catalog_count). The public methods are plain
defs on the mixin; subclasses reach them through normal instance dispatch (see the note below for the @OperationsMethod convention).Why a mixin and not inheritance? The shared behaviour cuts across Operations classes that have their own primary inheritance chain (BaseOperations); a mixin keeps the catalog-import surface composable with that chain without disturbing it.
- CATALOG_FILE = None¶
- CATALOG_SUBDIR = 'Templates'¶
- CATALOG_PARSER = None¶
- CATALOG_PREFIX_WRITE = None¶
- DOMAIN_LABEL = 'item'¶
- ImportCatalog(progress=None)[source]¶
Import the configured SIL catalog into this project. Idempotent.
Each catalog entry is matched against existing items by its canonical GUID. Entries whose GUID already exists are skipped. New entries are created with the canonical GUID + per-WS localized name/abbreviation/description, and a CatalogSourceId tag for later FixGuidsAgainstCatalog() repair.
- Parameters:
progress – Optional callable accepting (count, total, name) for progress reporting. May be None.
- Returns:
Created/skipped counts, list of created GUIDs, and any human-readable warnings raised during import.
- Return type:
- Raises:
FP_ReadOnlyError – If the project is not opened with write enabled.
FileNotFoundError – If the catalog file is not found under FWCodeDir.
FP_ParameterError – For domain-specific preconditions (e.g. missing PhFeatureSystemOA on the project).
- CreateFromCatalog(source_id, parent=None)[source]¶
Create a single item from the configured catalog using the canonical GUID and all localized data available for the WSes the project has.
Idempotent: if an item with the catalog’s canonical GUID already exists in the project, that existing item is returned unchanged.
- Parameters:
source_id (str) – Catalog id, with or without a known catalog prefix (
"GOLD:","PHON:"). e.g."GOLD:Adjective"or"Adjective";"PHON:fPAConsonantal"or"fPAConsonantal".parent – Optional LCM object to attach the new item under. For hierarchical domains (POS), this becomes the parent POS. For flat domains (PhonFeats), this is ignored.
- Returns:
The created (or pre-existing) LCM object, cast via _cast_to_domain.
- Raises:
FP_ReadOnlyError – If the project is not opened with write enabled.
FP_ParameterError – If source_id is not present in the catalog, or for domain-specific preconditions.
FileNotFoundError – If the catalog is not found under FWCodeDir.
- FixGuidsAgainstCatalog()[source]¶
Scan items in this project; for any whose CatalogSourceId matches a catalog entry but whose GUID differs from the catalog’s canonical GUID, create a replacement with the correct GUID, transfer references via MergeObject, and remove the old item.
- Returns:
One
(old_name, old_guid, new_guid)tuple per item repaired. Empty list if everything is already canonical.- Return type:
list[tuple]
- Raises:
FP_ReadOnlyError – If the project is not opened with write enabled.
FP_ParameterError – If MergeObject fails for any candidate (silently removing the old item would orphan incoming references, so we re-raise the LCM error).
flexicon.code.Shared.lcm_constants module¶
LCM API constants and property type definitions.
- class flexicon.code.Shared.lcm_constants.CellarPropertyType[source]¶
Bases:
objectType constants for LCM Cellar properties.
These constants identify the type of each property in the LibLCM data model. Values match SIL.LCModel.Core.Cellar.CellarPropertyType in the C# API.
- Reference:
SIL.LCModel.Core.Cellar.CellarPropertyType (from FLExLCM.py)
- PropType_String = 2¶
- PropType_Integer = 6¶
- PropType_Boolean = 20¶
- PropType_MultiString = 13¶
- PropType_MultiUnicode = 14¶
- PropType_Time = 4¶
- PropType_Guid = 15¶
- PropType_GenDate = 16¶
- PropType_Binary = 17¶
- PropType_Float = 5¶
- PropType_Object = 23¶
- PropType_Sequence = 26¶
- PropType_ReferenceSequence = 27¶
- PropType_ReferenceAtomic = 28¶
- PropType_ReferenceCollection = 29¶
flexicon.code.Shared.rule_patterns module¶
Pattern-element types for the PhonologicalRuleOperations.WireRule composer.
These are inert dataclasses used to describe rule contexts at the wrapper level. The composer translates them into LCM simple-context objects.
Usage:
from flexlibs2 import Seg, NC, Boundary
# Build context elements
seg_t = Seg(phoneme_t)
vowels_back = NC(vowel_class, plus=[alpha_back])
word_bdry = Boundary("#")
Greek-variable identity is preserved by re-using the SAME IPhFeatureConstraint object across multiple NC pattern elements.
- class flexicon.code.Shared.rule_patterns.Seg(phoneme: object)[source]¶
Bases:
objectA single-phoneme pattern element.
- Parameters:
phoneme – An IPhPhoneme, HVO (int), or wrapper representing a single phoneme.
Notes
Seg carries no alpha-feature constraints: LCM’s
IPhSimpleContextSeghas noPlusConstrRS/MinusConstrRSslots – onlyIPhSimpleContextNCdoes. To express alpha-feature constraints on a single phoneme, wrap it in a singletonIPhNaturalClassand useNC(class, plus=[...], minus=[...])instead. A singleton NC can be reused across rules that target the same phoneme. (Linguistic context: e.g. Bantu N-place assimilation – see issue #23.)- phoneme: object¶
- class flexicon.code.Shared.rule_patterns.NC(natural_class: object, plus: tuple = (), minus: tuple = ())[source]¶
Bases:
objectA natural-class pattern element, optionally with alpha-feature constraints.
- Parameters:
natural_class – An IPhNaturalClass, HVO (int), or wrapper.
plus – Sequence of IPhFeatureConstraint objects to attach to
PlusConstrRS(positive alpha-variable bindings, e.g. [+aBack]).minus – Sequence of IPhFeatureConstraint objects to attach to
MinusConstrRS(negative alpha-variable bindings, e.g. [-aBack]).
Notes
Re-use the SAME IPhFeatureConstraint object across multiple positions to express alpha/beta/gamma agreement.
- natural_class: object¶
- plus: tuple = ()¶
- minus: tuple = ()¶
- class flexicon.code.Shared.rule_patterns.Boundary(marker: str = '#')[source]¶
Bases:
objectA boundary marker pattern element, identified by its FW-shipped name.
- Parameters:
marker – One of FieldWorks’ standard boundary marker names. The default project ships with
"#"(word boundary),"+"(morpheme boundary), and"."(syllable boundary).
Notes
Boundary elements appear only in left/right contexts (never in the structural change). The composer looks the marker up by name from
PhonemeSetsOS[0].BoundaryMarkersOCrather than creating new markers.- marker: str = '#'¶
flexicon.code.Shared.smart_collection module¶
Base class for smart collections with type-aware display and filtering.
This module provides SmartCollection, a base class for creating collection objects that present multiple concrete types in a unified way while still showing the type diversity to the user.
- The Problem:
When you call GetAll() on an operation class that returns objects with multiple concrete implementations (e.g., phonological rules), the collection mixes different types. Users need to: - See which types are represented - Filter by type if they want to - Work with all types together without manual casting
- The Solution:
SmartCollection provides: - __str__() that shows type breakdown by ClassName count - by_type() method to filter to specific concrete types - filter() abstract method for subclasses to define filtering logic - Standard Python collection methods (__iter__, __len__)
Example:
from flexlibs2.code.Shared.smart_collection import SmartCollection
class RuleCollection(SmartCollection):
def filter(self, **criteria):
'''Filter rules by name, direction, etc.'''
filtered = [r for r in self._items if self._matches(r, criteria)]
return RuleCollection(filtered)
# Usage
rules = phonRuleOps.GetAll() # Returns RuleCollection with 12 rules
print(rules) # Shows type breakdown
# "Phonological Rules (12 total)"
# " PhRegularRule: 7 (58%)"
# " PhMetathesisRule: 3 (25%)"
# " PhReduplicationRule: 2 (17%)"
# Filter to specific type
regular_rules = rules.by_type('PhRegularRule')
print(len(regular_rules)) # 7
# Use custom filter
voicing_rules = rules.filter(name_contains='voicing')
- Usage Notes:
Subclasses must override filter() to provide filtering logic
Collections are iterable and support len()
Type breakdown is shown on str() for transparency
by_type() is implemented in base class
- class flexicon.code.Shared.smart_collection.SmartCollection(items=None)[source]¶
Bases:
IterableBase class for smart collections with type awareness and unified filtering.
Provides standard collection operations (__iter__, __len__, __str__) plus type-aware features (by_type filtering, type breakdown display).
Subclasses override filter() to define domain-specific filtering logic.
- Variables:
_items – The list of wrapped LCM objects in the collection
- by_type(class_name)[source]¶
Filter the collection to items of a specific concrete type.
Returns a new collection containing only items whose ClassName matches the specified class_name. Useful for operating on a specific concrete type (e.g., just PhRegularRule, not all rules).
- Parameters:
class_name – The ClassName to filter by (e.g., ‘PhRegularRule’).
- Returns:
New collection with filtered items.
- Return type:
Example:
all_rules = phonRuleOps.GetAll() regular_rules = all_rules.by_type('PhRegularRule') print(f"Found {len(regular_rules)} regular rules") # Chain with custom filtering voicing_regular = regular_rules.filter(name_contains='voicing')
Notes
Returns a new collection (doesn’t modify original)
Returns empty collection if no items match
Use ClassName strings like ‘PhRegularRule’, ‘MoStemMsa’, etc.
- filter(**criteria)[source]¶
Filter the collection using domain-specific criteria.
This is an abstract method that subclasses override to provide filtering logic specific to their domain. For example: - RuleCollection.filter(name_contains=’voicing’, direction=’LTR’) - EntryCollection.filter(gloss_contains=’to run’, pos=’verb’)
Subclasses should return a new collection of the same type with items matching all criteria.
- Parameters:
**criteria – Domain-specific filter criteria.
- Returns:
New collection with filtered items.
- Return type:
- Raises:
NotImplementedError – Base class doesn’t implement filtering. Subclasses must override this method.
Example:
# Subclass implementation class RuleCollection(SmartCollection): def filter(self, name_contains=None, direction=None): filtered = self._items if name_contains: filtered = [ r for r in filtered if name_contains in r.Name ] if direction: filtered = [ r for r in filtered if r.Direction == direction ] return RuleCollection(filtered) # Usage voicing_rules = rules.filter(name_contains='voicing')
- append(item)[source]¶
Add an item to the collection.
- Parameters:
item – Item to add.
Example:
rules = SmartCollection() rules.append(new_rule)
flexicon.code.Shared.string_utils module¶
- flexicon.code.Shared.string_utils.normalize_text(text)[source]¶
Normalize a text value from LCM, converting FLEx’s null marker to empty string.
FLEx/LCM uses
***as a placeholder when multilingual string fields (IMultiString, IMultiUnicode) have no value set. This function normalizes such values to empty strings for consistent handling.- Parameters:
text – A string value from an LCM text field, or None
- Returns:
The original text if it has content, or “” if None/empty/
***
Example
>>> from flexlibs2.code.Shared.string_utils import normalize_text >>> normalize_text("***") '' >>> normalize_text(None) '' >>> normalize_text("hello") 'hello' >>> normalize_text("") ''
- flexicon.code.Shared.string_utils.normalize_match_key(text, casefold=True)[source]¶
Produce a key suitable for matching a Python-side string against an FLEx-stored multilingual string value.
FLEx stores all IMultiString/IMultiUnicode values in NFD; Python source is typically NFC. Without normalization, any string containing combined diacritics will silently fail to match. Apply this to BOTH sides of any Find/Exists comparison.
- Parameters:
text – Input string (may be None, ‘’, or
***).casefold – If True (default), apply str.casefold() after NFD normalization. Pass False for case-sensitive Find methods. Use casefold (not lower) for correct handling of Turkish dotted/dotless I, German ess-zett, etc.
- Returns:
Normalized string. Empty string for None/empty/
***inputs.
Example
>>> needle = normalize_match_key("oo", casefold=False) >>> haystack = normalize_match_key(ITsString(p.Name.get_String(ws)).Text, ... casefold=False) >>> needle == haystack # True even when Python NFC differs from LCM NFD True
- flexicon.code.Shared.string_utils.normalize_ws_handle(ws)[source]¶
Normalize a writing-system argument to an integer handle.
LCM methods such as
ITsMultiString.get_Stringrequire a plaininthandle. Users naturally obtain writing-system objects fromproject.WritingSystems(CoreWritingSystemDefinition) or pass an int they already have. This helper smooths over both cases so wrappers don’t expose a confusing pythonnetTypeErrorwhen the caller passes an object instead of a raw handle.- Parameters:
ws – An
inthandle, aCoreWritingSystemDefinition(or any object that exposes a.Handleattribute returning anint), orNone.- Returns:
inthandle, orNoneifwsisNone.- Raises:
TypeError – If
wsis notNone, not anint, and has no.Handleattribute.
Example
>>> from flexlibs2.code.Shared.string_utils import normalize_ws_handle >>> normalize_ws_handle(123) 123 >>> normalize_ws_handle(None) is None True >>> # CoreWritingSystemDefinition object with .Handle == 1 >>> normalize_ws_handle(ws_def) 1
- flexicon.code.Shared.string_utils.is_empty_text(text)[source]¶
Check if a text value from LCM is empty (None, empty string, or
***).- Parameters:
text – A string value from an LCM text field, or None
- Returns:
True if the text represents an empty/unset value
Example
>>> from flexlibs2.code.Shared.string_utils import is_empty_text >>> is_empty_text("***") True >>> is_empty_text(None) True >>> is_empty_text("") True >>> is_empty_text("hello") False
- flexicon.code.Shared.string_utils.best_analysis_text(multi_obj)[source]¶
Get the best analysis alternative text from an IMultiString/IMultiUnicode, normalized to empty string if unset.
This combines accessing .BestAnalysisAlternative.Text with null marker handling.
- Parameters:
multi_obj – An IMultiString or IMultiUnicode object, or None
- Returns:
The text content, or “” if None/empty/
***
Example
>>> text = best_analysis_text(sense.Definition) >>> text = best_analysis_text(pos.Name)
- flexicon.code.Shared.string_utils.best_vernacular_text(multi_obj)[source]¶
Get the best vernacular alternative text from an IMultiString/IMultiUnicode, normalized to empty string if unset.
This combines accessing .BestVernacularAlternative.Text with null marker handling.
- Parameters:
multi_obj – An IMultiString or IMultiUnicode object, or None
- Returns:
The text content, or “” if None/empty/
***
Example
>>> text = best_vernacular_text(entry.LexemeFormOA.Form)
- flexicon.code.Shared.string_utils.best_text(multi_obj)[source]¶
Get the best analysis-or-vernacular alternative text from an IMultiString/IMultiUnicode, normalized to empty string if unset.
This combines accessing .BestAnalysisVernacularAlternative.Text with null marker handling. Prefers analysis writing system, falls back to vernacular.
- Parameters:
multi_obj – An IMultiString or IMultiUnicode object, or None
- Returns:
The text content, or “” if None/empty/
***
Example
>>> text = best_text(sense.Gloss)
flexicon.code.Shared.wrapper_base module¶
Base wrapper class for LCM objects with intelligent property routing.
This module provides LCMObjectWrapper, a base class for creating wrapper objects that transparently handle the two-layer LCM type system:
Base Interface: Generic interface typed by pythonnet (e.g., IPhSegmentRule)
Concrete Type: Actual runtime type identified by ClassName attribute
Concrete Interface: Type-specific interface with additional properties
- The Problem:
In pythonnet, when you access objects from a collection, they’re typed as the base interface. Accessing concrete type-specific properties requires explicit casting based on the ClassName attribute.
- The Solution:
LCMObjectWrapper stores both the base interface and concrete type, then uses __getattr__() to route property access intelligently: - Try concrete type first (more specific properties) - Fall back to base interface if property doesn’t exist - Return None for missing properties instead of raising AttributeError
Example:
from flexlibs2.code.Shared.wrapper_base import LCMObjectWrapper
from flexlibs2.code.lcm_casting import cast_to_concrete
# Wrap an LCM object
rule = phonRuleOps.GetAll()[0] # Typed as IPhSegmentRule
wrapped = LCMObjectWrapper(rule)
# Access type-specific properties transparently
if wrapped.ClassName == 'PhRegularRule':
rhs_count = wrapped.RightHandSidesOS.Count # Works without casting!
# Check what properties are available
common_props = wrapped.get_property('StrucDescOS')
if common_props:
print(f"Rule has {len(common_props)} input contexts")
- Usage Notes:
Wrapper classes inherit from LCMObjectWrapper
Never access _obj or _concrete directly in subclasses
Use get_property() for safe access with defaults
Use class_type property to check the concrete type
- class flexicon.code.Shared.wrapper_base.LCMObjectWrapper(lcm_obj)[source]¶
Bases:
objectBase wrapper for LCM objects providing unified interface access.
Stores both the base interface and concrete type, routing property access intelligently to support the two-layer LCM type system transparently.
- Variables:
_obj – The base interface object (e.g., IPhSegmentRule)
_concrete – The concrete type object (e.g., IPhRegularRule)
- property class_type¶
Get the concrete class type as a string.
Returns the ClassName attribute, which uniquely identifies the concrete type of the wrapped object. This is the primary way to check which concrete interface the object implements.
- Returns:
- The ClassName (e.g., “PhRegularRule”, “PhMetathesisRule”,
”MoStemMsa”, “MoInflAffMsa”, etc.)
- Return type:
str
Example:
wrapped = LCMObjectWrapper(rule) if wrapped.class_type == 'PhRegularRule': # Object is a regular phonological rule pass elif wrapped.class_type == 'PhMetathesisRule': # Object is a metathesis rule pass
- get_property(prop_name, default=None)[source]¶
Safely get a property value with a fallback default.
Attempts to access a property on the wrapped object, returning a default value if the property doesn’t exist. This is safer than direct property access when you’re unsure whether a property exists on the wrapped object’s type.
- Parameters:
prop_name – Name of the property to access.
default – Value to return if property doesn’t exist. Default: None.
- Returns:
The property value if it exists, otherwise the default value.
Example:
# Safe access to type-specific properties rhs = wrapped.get_property('RightHandSidesOS') if rhs: print(f"Rule has {rhs.Count} RHS") # Check for optional properties frequency = wrapped.get_property('Frequency', 0) print(f"Rule frequency: {frequency}") # Provide meaningful defaults context_count = wrapped.get_property('StrucDescOS', []) print(f"Input contexts: {len(context_count)}")