#
# PublicationOperations.py
#
# Class: PublicationOperations
# Publication and publishing workflow operations for FieldWorks Language
# Explorer projects via SIL Language and Culture Model (LCM) API.
#
# Platform: Python.NET
# FieldWorks Version 9+
#
# Copyright 2025
#
# Import FLEx LCM types
from SIL.LCModel import (
ICmPossibility,
ICmPossibilityFactory,
ICmPossibilityRepository,
)
from SIL.LCModel.Core.KernelInterfaces import ITsString
from SIL.LCModel.Core.Text import TsStringUtils
from System import DateTime
# Import flexlibs exceptions
from ..FLExProject import (
FP_ParameterError,
FP_NullParameterError,
)
from ..BaseOperations import OperationsMethod, wrap_enumerable
from .possibility_item_base import PossibilityItemOperations
[docs]
class PublicationOperations(PossibilityItemOperations):
"""
This class provides operations for managing publications and publishing
workflows in a FieldWorks project.
Publications in FLEx define output formats for dictionary and text publishing.
They specify page layouts, formatting options, divisions (e.g., main entries,
minor entries), header/footer settings, and default publication types. These
are used when exporting dictionaries or texts to various formats.
Inherited CRUD Operations (from PossibilityItemOperations):
- GetAll() - Get all publications (NOTE: override handles flat parameter)
- Create() - Create a new publication
- Delete() - Delete a publication
- Duplicate() - Clone a publication
- Find() - Find by name
- Exists() - Check existence
- GetName() / SetName() - Get/set name
- GetDescription() / SetDescription() - Get/set description
- GetGuid() - Get GUID
- CompareTo() - Compare by name
Domain-Specific Methods (PublicationOperations):
- GetPageLayout() - Get page layout description
- SetPageLayout() - Set page layout description
- GetIsDefault() - Check if default publication
- SetIsDefault() - Set default publication
- GetPageHeight() - Get page height
- SetPageHeight() - Set page height
- GetPageWidth() - Get page width
- SetPageWidth() - Set page width
- GetDivisions() - Get publication divisions
- AddDivision() - Add a division
- GetHeaderFooter() - Get header/footer configuration
- GetIsLandscape() - Check landscape orientation
- GetSubPublications() - Get sub-publications
- GetParent() - Get parent publication
- GetDateCreated() - Get creation date
- GetDateModified() - Get modification date
This class should be accessed via FLExProject.Publications property.
Usage::
from flexlibs2 import FLExProject
project = FLExProject()
project.OpenProject("my project", writeEnabled=True)
# Get all publications
for pub in project.Publications.GetAll():
name = project.Publications.GetName(pub)
is_default = project.Publications.GetIsDefault(pub)
print(f"{name} (Default: {is_default})")
# Create a new publication
pub = project.Publications.Create("Web Dictionary")
# Set page layout and formatting
project.Publications.SetPageWidth(pub, 8.5)
project.Publications.SetPageHeight(pub, 11.0)
project.Publications.SetDescription(pub,
"Dictionary layout for web publication")
# Set as default publication
project.Publications.SetIsDefault(pub, True)
# Find a publication by name
main_pub = project.Publications.Find("Main Dictionary")
if main_pub:
width = project.Publications.GetPageWidth(main_pub)
height = project.Publications.GetPageHeight(main_pub)
print(f"Page size: {width} x {height} inches")
project.CloseProject()
"""
def __init__(self, project):
"""
Initialize PublicationOperations with a FLExProject instance.
Args:
project: The FLExProject instance to operate on.
"""
super().__init__(project)
def _get_item_class_name(self):
"""Get the item class name for error messages."""
return "Publication"
def _get_list_object(self):
"""Get the publications list container."""
return self.project.lexDB.PublicationTypesOA
# --- Core CRUD Operations ---
@wrap_enumerable
@OperationsMethod
def GetAll(self, recursive=True, **kwargs):
"""
Get all publications in the project.
Args:
recursive (bool): If True (default), returns every publication in
the hierarchy (depth-first, parents before children). If
False, returns only top-level publications and the caller
must descend via GetSubPublications.
Returns:
list: List of ICmPossibility objects representing publications.
Example:
>>> for pub in project.Publications.GetAll():
... print(project.Publications.GetName(pub)) # Includes variants at any depth
>>> # Top-level only
>>> for pub in project.Publications.GetAll(recursive=False):
... print(project.Publications.GetName(pub))
See Also:
Find, GetSubPublications
"""
self._RejectLegacyKwargs(kwargs, {
"flat": ("recursive", "semantics inverted: flat=True is now recursive=True"),
})
list_obj = self._get_list_object()
if not list_obj:
return []
if not recursive:
return list(list_obj.PossibilitiesOS)
all_pubs = []
def walk(collection):
for pub in collection:
all_pubs.append(pub)
if hasattr(pub, "SubPossibilitiesOS") and pub.SubPossibilitiesOS.Count > 0:
walk(pub.SubPossibilitiesOS)
walk(list_obj.PossibilitiesOS)
return all_pubs
# --- Publishing Properties ---
@OperationsMethod
def GetPageLayout(self, publication_or_hvo, wsHandle=None):
"""
Get the page layout description for a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
wsHandle: Optional writing system handle. Defaults to analysis WS.
Returns:
str: Page layout description, or empty string if not set.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> layout = project.Publications.GetPageLayout(pub)
>>> print(layout)
Two-column layout with headers and footers
Notes:
- Returns empty string if page layout not set
- Layout description is free-form text
- Can describe columns, margins, orientation, etc.
- Different from page dimensions (width/height)
See Also:
SetPageLayout, GetPageWidth, GetPageHeight
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
wsHandle = self._PossibilityItemOperations__WSHandle(wsHandle)
# Use Abbreviation field for page layout description
if hasattr(publication, "Abbreviation"):
layout = ITsString(publication.Abbreviation.get_String(wsHandle)).Text
return layout or ""
return ""
@OperationsMethod
def SetPageLayout(self, publication_or_hvo, layout, wsHandle=None):
"""
Set the page layout description for a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
layout (str): Page layout description.
wsHandle: Optional writing system handle. Defaults to analysis WS.
Raises:
FP_ReadOnlyError: If the project is not opened with write enabled.
FP_NullParameterError: If publication_or_hvo or layout is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> project.Publications.SetPageLayout(pub,
... "Two-column layout with running headers")
>>> # Clear layout description
>>> project.Publications.SetPageLayout(pub, "")
Notes:
- Empty string is allowed (clears the layout description)
- Layout description is stored in the specified writing system
- Use to describe columns, margins, orientation, etc.
- Actual page dimensions set with SetPageWidth/SetPageHeight
See Also:
GetPageLayout, SetPageWidth, SetPageHeight
"""
self._EnsureWriteEnabled()
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
self._ValidateParam(layout, "layout")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
wsHandle = self._PossibilityItemOperations__WSHandle(wsHandle)
if hasattr(publication, "Abbreviation"):
with self._TransactionCM("Set publication page layout"):
mkstr = TsStringUtils.MakeString(layout, wsHandle)
publication.Abbreviation.set_String(wsHandle, mkstr)
# Update modification date
publication.DateModified = DateTime.Now
@OperationsMethod
def GetIsDefault(self, publication_or_hvo):
"""
Check if a publication is the default publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
Returns:
bool: True if this is the default publication, False otherwise.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> for pub in project.Publications.GetAll():
... name = project.Publications.GetName(pub)
... is_default = project.Publications.GetIsDefault(pub)
... default_marker = " [DEFAULT]" if is_default else ""
... print(f"{name}{default_marker}")
Main Dictionary [DEFAULT]
Root-based Dictionary
Thematic Dictionary
>>> # Find the default publication
>>> default_pub = None
>>> for pub in project.Publications.GetAll():
... if project.Publications.GetIsDefault(pub):
... default_pub = pub
... break
Notes:
- Only one publication can be the default
- Default publication is used when no specific publication is selected
- Returns False if publication is not default
- If no default is set, all publications return False
See Also:
SetIsDefault, Find
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
# Check if this publication is the default
# Default is typically the first publication or marked by IsDefault property
pub_list = self.project.lexDB.PublicationTypesOA
if pub_list and pub_list.PossibilitiesOS.Count > 0:
# The default publication is typically the first one
default_pub = pub_list.PossibilitiesOS[0]
return publication.Hvo == default_pub.Hvo
return False
@OperationsMethod
def SetIsDefault(self, publication_or_hvo, is_default):
"""
Set whether a publication is the default publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
is_default (bool): True to make this the default, False otherwise.
Raises:
FP_ReadOnlyError: If the project is not opened with write enabled.
FP_NullParameterError: If publication_or_hvo or is_default is None.
Example:
>>> # Set a publication as default
>>> pub = project.Publications.Find("Web Dictionary")
>>> project.Publications.SetIsDefault(pub, True)
>>> # Remove default status (sets first publication as default)
>>> project.Publications.SetIsDefault(pub, False)
Notes:
- Only one publication can be default at a time
- Setting a publication as default makes it the first in the list
- If is_default is False, publication is moved from first position
- Default publication is used when no specific publication is selected
See Also:
GetIsDefault, Create
"""
self._EnsureWriteEnabled()
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
self._ValidateParam(is_default, "is_default")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
pub_list = self.project.lexDB.PublicationTypesOA
if not pub_list:
return
# To make a publication default, move it to the first position
with self._TransactionCM("Set default publication"):
if is_default:
# Remove from current position
if publication in pub_list.PossibilitiesOS:
pub_list.PossibilitiesOS.Remove(publication)
# Insert at first position
pub_list.PossibilitiesOS.Insert(0, publication)
else:
# If removing default status, move to end
if publication in pub_list.PossibilitiesOS:
current_index = pub_list.PossibilitiesOS.IndexOf(publication)
if current_index == 0: # Is currently default
pub_list.PossibilitiesOS.Remove(publication)
pub_list.PossibilitiesOS.Add(publication)
# --- Formatting Properties ---
@OperationsMethod
def GetPageHeight(self, publication_or_hvo):
"""
Get the page height for a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
Returns:
float or None: Page height in inches, or None if not set.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> height = project.Publications.GetPageHeight(pub)
>>> if height:
... print(f"Page height: {height} inches")
Page height: 11.0 inches
>>> # Get both dimensions
>>> width = project.Publications.GetPageWidth(pub)
>>> height = project.Publications.GetPageHeight(pub)
>>> if width and height:
... print(f"Page size: {width}\" x {height}\"")
Notes:
- Returns None if page height is not set
- Height is in inches (standard US measurement)
- Common sizes: 11.0 (Letter), 11.69 (A4), 14.0 (Legal)
- Use with GetPageWidth() to get full page dimensions
See Also:
SetPageHeight, GetPageWidth
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
# Store in SortKey2 field (encoded as integer, divide by 1000 for inches)
if hasattr(publication, "SortKey2") and publication.SortKey2 != 0:
return float(publication.SortKey2) / 1000.0
return None
@OperationsMethod
def SetPageHeight(self, publication_or_hvo, height):
"""
Set the page height for a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
height (float): Page height in inches.
Raises:
FP_ReadOnlyError: If the project is not opened with write enabled.
FP_NullParameterError: If publication_or_hvo or height is None.
FP_ParameterError: If height is not positive.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> # Set letter-size height
>>> project.Publications.SetPageHeight(pub, 11.0)
>>> # Set A4 height
>>> project.Publications.SetPageHeight(pub, 11.69)
>>> # Set legal-size height
>>> project.Publications.SetPageHeight(pub, 14.0)
Notes:
- Height must be positive
- Height is stored in inches
- Common heights: 11.0 (Letter), 11.69 (A4), 14.0 (Legal)
- Set both width and height for complete page dimensions
See Also:
GetPageHeight, SetPageWidth
"""
self._EnsureWriteEnabled()
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
self._ValidateParam(height, "height")
try:
h = float(height)
except (TypeError, ValueError):
raise FP_ParameterError("Height must be numeric")
if h <= 0:
raise FP_ParameterError("Height must be positive")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
# Store in SortKey2 field (multiply by 1000 to store as integer)
if hasattr(publication, "SortKey2"):
with self._TransactionCM("Set publication page height"):
publication.SortKey2 = int(h * 1000)
# Update modification date
publication.DateModified = DateTime.Now
@OperationsMethod
def GetPageWidth(self, publication_or_hvo):
"""
Get the page width for a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
Returns:
float or None: Page width in inches, or None if not set.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> width = project.Publications.GetPageWidth(pub)
>>> if width:
... print(f"Page width: {width} inches")
Page width: 8.5 inches
>>> # Check if dimensions are set
>>> width = project.Publications.GetPageWidth(pub)
>>> height = project.Publications.GetPageHeight(pub)
>>> if width and height:
... aspect = width / height
... print(f"Aspect ratio: {aspect:.2f}")
Notes:
- Returns None if page width is not set
- Width is in inches (standard US measurement)
- Common sizes: 8.5 (Letter/Legal), 8.27 (A4)
- Use with GetPageHeight() to get full page dimensions
See Also:
SetPageWidth, GetPageHeight
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
# Store in SortKey field (encoded as integer, divide by 1000 for inches)
if hasattr(publication, "SortKey") and publication.SortKey != 0:
return float(publication.SortKey) / 1000.0
return None
@OperationsMethod
def SetPageWidth(self, publication_or_hvo, width):
"""
Set the page width for a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
width (float): Page width in inches.
Raises:
FP_ReadOnlyError: If the project is not opened with write enabled.
FP_NullParameterError: If publication_or_hvo or width is None.
FP_ParameterError: If width is not positive.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> # Set letter-size width
>>> project.Publications.SetPageWidth(pub, 8.5)
>>> # Set A4 width
>>> project.Publications.SetPageWidth(pub, 8.27)
>>> # Set custom width
>>> project.Publications.SetPageWidth(pub, 7.0)
Notes:
- Width must be positive
- Width is stored in inches
- Common widths: 8.5 (Letter/Legal), 8.27 (A4)
- Set both width and height for complete page dimensions
See Also:
GetPageWidth, SetPageHeight
"""
self._EnsureWriteEnabled()
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
self._ValidateParam(width, "width")
try:
w = float(width)
except (TypeError, ValueError):
raise FP_ParameterError("Width must be numeric")
if w <= 0:
raise FP_ParameterError("Width must be positive")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
# Store in SortKey field (multiply by 1000 to store as integer)
if hasattr(publication, "SortKey"):
with self._TransactionCM("Set publication page width"):
publication.SortKey = int(w * 1000)
# Update modification date
publication.DateModified = DateTime.Now
# --- Divisions and Structure ---
@OperationsMethod
def GetDivisions(self, publication_or_hvo):
"""
Get the publication divisions (e.g., main entries, minor entries).
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
Returns:
list: List of ICmPossibility objects representing divisions.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> divisions = project.Publications.GetDivisions(pub)
>>> for div in divisions:
... name = ITsString(div.Name.BestAnalysisAlternative).Text
... print(f"Division: {name}")
Division: Main Entries
Division: Minor Entries
Division: Back Matter
Notes:
- Returns empty list if no divisions
- Divisions organize content into sections
- Common divisions: Main Entries, Minor Entries, Subentries
- Divisions are represented as sub-possibilities
See Also:
AddDivision, GetSubPublications
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
# Divisions are stored as sub-possibilities
if hasattr(publication, "SubPossibilitiesOS"):
return list(publication.SubPossibilitiesOS)
return []
@OperationsMethod
def AddDivision(self, publication_or_hvo, division_name, wsHandle=None):
"""
Add a division to a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
division_name (str): Name of the division (e.g., "Main Entries").
wsHandle: Optional writing system handle. Defaults to analysis WS.
Returns:
ICmPossibility: The newly created division object.
Raises:
FP_ReadOnlyError: If the project is not opened with write enabled.
FP_NullParameterError: If publication_or_hvo or division_name is None.
FP_ParameterError: If division_name is empty.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> # Add standard divisions
>>> main = project.Publications.AddDivision(pub, "Main Entries")
>>> minor = project.Publications.AddDivision(pub, "Minor Entries")
>>> back = project.Publications.AddDivision(pub, "Back Matter")
>>> # Verify divisions were added
>>> divisions = project.Publications.GetDivisions(pub)
>>> print(f"Publication has {len(divisions)} divisions")
Notes:
- Division name should be descriptive
- Common divisions: Main Entries, Minor Entries, Subentries
- Divisions organize publication content
- Multiple divisions can be added to one publication
See Also:
GetDivisions, Create
"""
self._EnsureWriteEnabled()
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
self._ValidateParam(division_name, "division_name")
if not division_name or not division_name.strip():
raise FP_ParameterError("Division name cannot be empty")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
wsHandle = self._PossibilityItemOperations__WSHandle(wsHandle)
# Create the new division using the factory
factory = self.project.project.ServiceLocator.GetService(ICmPossibilityFactory)
with self._TransactionCM(f"Add division {division_name!r}"):
new_division = factory.Create()
# Add to publication's sub-possibilities (must be done before setting properties)
if hasattr(publication, "SubPossibilitiesOS"):
publication.SubPossibilitiesOS.Add(new_division)
# Set name
mkstr_name = TsStringUtils.MakeString(division_name, wsHandle)
new_division.Name.set_String(wsHandle, mkstr_name)
# Set creation date
new_division.DateCreated = DateTime.Now
return new_division
@OperationsMethod
def GetHeaderFooter(self, publication_or_hvo, wsHandle=None):
"""
Get the header/footer configuration for a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
wsHandle: Optional writing system handle. Defaults to analysis WS.
Returns:
str: Header/footer configuration text, or empty string if not set.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> header = project.Publications.GetHeaderFooter(pub)
>>> print(header)
Header: Dictionary title | Page number
Footer: Copyright notice
Notes:
- Returns empty string if header/footer not set
- Can describe header and footer content
- Free-form text description
- Actual header/footer rendering depends on export format
See Also:
GetPageLayout, GetDescription
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
wsHandle = self._PossibilityItemOperations__WSHandle(wsHandle)
# Use Comment field for header/footer information
if hasattr(publication, "Comment"):
header = ITsString(publication.Comment.get_String(wsHandle)).Text
return header or ""
return ""
@OperationsMethod
def GetIsLandscape(self, publication_or_hvo):
"""
Check if publication uses landscape orientation.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
Returns:
bool: True if landscape orientation, False if portrait or not set.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> is_landscape = project.Publications.GetIsLandscape(pub)
>>> if is_landscape:
... print("Landscape orientation")
... else:
... print("Portrait orientation")
Portrait orientation
>>> # Check orientation and page dimensions
>>> width = project.Publications.GetPageWidth(pub)
>>> height = project.Publications.GetPageHeight(pub)
>>> is_landscape = project.Publications.GetIsLandscape(pub)
>>> orientation = "Landscape" if is_landscape else "Portrait"
>>> print(f"{orientation}: {width}\" x {height}\"")
Portrait: 8.5" x 11.0"
Notes:
- READ-ONLY property - cannot be set directly
- Orientation is typically inferred from page width vs. height
- True indicates landscape (width > height)
- False indicates portrait (height >= width)
- Returns False if orientation not set or if dimensions are equal
- Used when exporting dictionaries or texts
See Also:
GetPageWidth, GetPageHeight, GetPageLayout
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
# Check for IsLandscape property
if hasattr(publication, "IsLandscape"):
return bool(publication.IsLandscape)
return False
# --- Hierarchical Operations ---
@OperationsMethod
def GetSubPublications(self, publication_or_hvo, recursive=True):
"""
Get the sub-publications of a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
recursive (bool): If True (default), returns every descendant
sub-publication (depth-first, parents before children). If
False, returns only direct children.
Returns:
list: List of ICmPossibility sub-publication objects.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> for sub in project.Publications.GetSubPublications(pub):
... print(project.Publications.GetName(sub)) # All descendants
>>> # Direct children only
>>> for sub in project.Publications.GetSubPublications(pub, recursive=False):
... print(project.Publications.GetName(sub))
See Also:
GetParent, GetDivisions
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
if not hasattr(publication, "SubPossibilitiesOS"):
return []
if not recursive:
return list(publication.SubPossibilitiesOS)
result = []
def walk(collection):
for child in collection:
result.append(child)
if hasattr(child, "SubPossibilitiesOS") and child.SubPossibilitiesOS.Count > 0:
walk(child.SubPossibilitiesOS)
walk(publication.SubPossibilitiesOS)
return result
@OperationsMethod
def GetParent(self, publication_or_hvo):
"""
Get the parent publication of a sub-publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
Returns:
ICmPossibility or None: The parent publication, or None if top-level.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Web Dictionary Variant")
>>> parent = project.Publications.GetParent(pub)
>>> if parent:
... parent_name = project.Publications.GetName(parent)
... print(f"Parent: {parent_name}")
Notes:
- Returns None for top-level publications
- Parent is determined by ownership hierarchy
- Use for building breadcrumb navigation
See Also:
GetSubPublications
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
owner = publication.Owner
# Check if owner is a publication (sub-publication) or the list (top-level)
if owner and hasattr(owner, "ClassName"):
if owner.ClassName == "CmPossibility":
return ICmPossibility(owner)
return None
# --- Metadata Operations ---
@OperationsMethod
def GetDateCreated(self, publication_or_hvo):
"""
Get the creation date of a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
Returns:
System.DateTime or None: The creation date/time, or None if not set.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> date = project.Publications.GetDateCreated(pub)
>>> if date:
... print(f"Created: {date}")
Created: 11/23/2025 10:30:45 AM
>>> # Sort publications by creation date
>>> pubs = project.Publications.GetAll()
>>> sorted_pubs = sorted(pubs,
... key=lambda p: project.Publications.GetDateCreated(p) or DateTime.MinValue)
Notes:
- DateCreated is set automatically when publication is created
- Returns System.DateTime object
- Can be None for publications without creation date
- Use for tracking when publications were added to project
See Also:
GetDateModified, Create
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
if hasattr(publication, "DateCreated"):
return publication.DateCreated
return None
@OperationsMethod
def GetDateModified(self, publication_or_hvo):
"""
Get the last modification date of a publication.
Args:
publication_or_hvo: Either an ICmPossibility publication object or its HVO.
Returns:
System.DateTime or None: The modification date/time, or None if not set.
Raises:
FP_NullParameterError: If publication_or_hvo is None.
Example:
>>> pub = project.Publications.Find("Main Dictionary")
>>> modified = project.Publications.GetDateModified(pub)
>>> if modified:
... print(f"Last modified: {modified}")
Last modified: 11/23/2025 2:15:30 PM
>>> # Find recently modified publications
>>> from System import DateTime
>>> one_week_ago = DateTime.Now.AddDays(-7)
>>> pubs = project.Publications.GetAll()
>>> recent = [p for p in pubs
... if project.Publications.GetDateModified(p) and
... project.Publications.GetDateModified(p) > one_week_ago]
Notes:
- DateModified is updated when properties change
- Returns System.DateTime object
- May be None if publication has never been modified
- Useful for tracking publication updates
See Also:
GetDateCreated, SetName, SetDescription
"""
self._ValidateParam(publication_or_hvo, "publication_or_hvo")
publication = self._PossibilityItemOperations__ResolveObject(publication_or_hvo)
if hasattr(publication, "DateModified"):
return publication.DateModified
return None