odmlib
Submodules
builder module
Optional builder/fluent API for constructing ODM documents.
The builder provides a chainable interface for constructing complex documents with less boilerplate. It wraps the standard odmlib model classes and is purely additive — all existing APIs continue to work unchanged.
Example:
from odmlib.builder import ODMBuilder
odm = (ODMBuilder("odm_1_3_2")
.set_file(FileOID="F.001", FileType="Snapshot",
CreationDateTime="2024-01-01T00:00:00")
.add_study(OID="S.001",
study_name="My Study",
study_description="A study",
protocol_name="PROT-001")
.add_metadata_version(OID="MDV.001", Name="Version 1")
.add_item_group_def(OID="IG.DM", Name="Demographics", Repeating="No")
.add_item_ref(ItemOID="IT.SUBJID", Mandatory="Yes", OrderNumber=1)
.add_item_ref(ItemOID="IT.AGE", Mandatory="No", OrderNumber=2)
.build())
- class builder.ODMBuilder(model_package='odm_1_3_2')[source]
Bases:
objectFluent builder for constructing ODM documents.
Maintains state for the currently active Study, MetaDataVersion, and ItemGroupDef so that
add_*calls automatically append to the right parent.Works with
odm_1_3_2,define_2_0,define_2_1andodm_2_0. Model-shape differences are handled automatically — notably the ODM 2.0Study(scalarStudyName/ProtocolName, noGlobalVariables) and its object-valuedDescription. Note that ODM 2.0 is structurally flatter:StudyEventDefreferencesItemGroupRefdirectly (there is noFormDef/FormRef), so the form-level helpers do not apply toodm_2_0.- Parameters:
model_package (str) – The odmlib model package to use. Defaults to
"odm_1_3_2".
- set_file(**kwargs)[source]
Set ODM file-level attributes (FileOID, FileType, CreationDateTime, …).
These are passed directly to the
ODMconstructor whenbuild()is called.- Returns:
self, for chaining.
- Parameters:
kwargs (Any)
- Return type:
- add_study(OID, study_name, study_description, protocol_name, **kwargs)[source]
Add a Study element.
The Study is constructed in whichever shape the active model uses:
ODM 1.3.2 / Define-XML: a
GlobalVariableselement wrappingStudyName/StudyDescription/ProtocolNamechildren.ODM 2.0: scalar
StudyName/ProtocolNameattributes onStudyplus an object-valuedDescription(there is noGlobalVariableselement in ODM 2.0).
- Parameters:
- Returns:
self, for chaining.
- Return type:
- add_metadata_version(**kwargs)[source]
Add a MetaDataVersion to the current Study.
- Parameters:
kwargs (Any) – MetaDataVersion attributes (OID, Name, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no Study has been added yet.
- Return type:
- add_item_group_def(**kwargs)[source]
Add an ItemGroupDef to the current MetaDataVersion.
- Parameters:
kwargs (Any) – ItemGroupDef attributes (OID, Name, Repeating, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no MetaDataVersion has been added yet.
- Return type:
- add_item_ref(**kwargs)[source]
Add an ItemRef to the current ItemGroupDef.
- Parameters:
kwargs (Any) – ItemRef attributes (ItemOID, Mandatory, OrderNumber, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no ItemGroupDef has been added yet.
- Return type:
- add_item_def(**kwargs)[source]
Add an ItemDef to the current MetaDataVersion.
- Parameters:
kwargs (Any) – ItemDef attributes (OID, Name, DataType, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no MetaDataVersion has been added yet.
- Return type:
- add_code_list(OID, Name, DataType, items=None, **kwargs)[source]
Add a CodeList to the current MetaDataVersion.
- Parameters:
OID (str) – CodeList OID.
Name (str) – CodeList name.
DataType (str) – Coded value data type.
items (list | None) – Optional list of dicts. Each dict must have a
"CodedValue"key and may have a"Decode"key (a plain English label string). If"Decode"is present a CodeListItem is created; otherwise an EnumeratedItem.kwargs (Any) – Additional CodeList attributes.
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no MetaDataVersion has been added yet.
- Return type:
- with_description(text, lang='en')[source]
Attach a Description to the most recently created element.
Applies to the most recently created ItemGroupDef or ItemDef. Falls back to the current MetaDataVersion if neither is set.
- Parameters:
- Returns:
self, for chaining.
- Return type:
- add_study_event_def(**kwargs)[source]
Add a StudyEventDef to the current MetaDataVersion.
The StudyEventDef is appended to
MetaDataVersion.StudyEventDefand becomes the current study event so that subsequentadd_form_ref()(ODM 1.3.2) oradd_item_group_ref()(ODM 2.0) calls attach to it. This does not create a Protocol reference — useadd_study_event_ref()for that.- Parameters:
kwargs (Any) – StudyEventDef attributes (OID, Name, Repeating, Type, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no MetaDataVersion has been added yet.
- Return type:
- add_study_event_ref(**kwargs)[source]
Add a StudyEventRef to the current MetaDataVersion’s Protocol.
The Protocol element is created automatically if it does not exist yet.
ODM 1.3.2 / Define-XML only. The ODM 2.0 XSD has no
Protocol/StudyEventRef: a Protocol referencesStudyEventGroupRef, andStudyEventReflives one level down onStudyEventGroupDef. Calling this underodm_2_0therefore raises rather than emitting schema-invalid markup — build the StudyEventGroupDef yourself and graft it on withattach().Changed in version 0.2.1: Raises under
odm_2_0instead of silently producing an invalidProtocol/StudyEventRef.- Parameters:
kwargs (Any) – StudyEventRef attributes (StudyEventOID, Mandatory, OrderNumber, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no MetaDataVersion has been added yet, or if the active model is ODM 2.0.
- Return type:
- add_form_def(**kwargs)[source]
Add a FormDef to the current MetaDataVersion (ODM 1.3.2 only).
Becomes the current form so that
add_item_group_ref()attaches its ItemGroupRefs here.- Parameters:
kwargs (Any) – FormDef attributes (OID, Name, Repeating, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no MetaDataVersion yet, or model is ODM 2.0.
- Return type:
- add_form_ref(**kwargs)[source]
Add a FormRef to the current StudyEventDef (ODM 1.3.2 only).
- Parameters:
kwargs (Any) – FormRef attributes (FormOID, Mandatory, OrderNumber, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no StudyEventDef yet, or model is ODM 2.0.
- Return type:
- add_item_group_ref(**kwargs)[source]
Add an ItemGroupRef to the appropriate parent.
In ODM 1.3.2 / Define-XML the ItemGroupRef is added to the current FormDef (call
add_form_def()first). In ODM 2.0 — which has no FormDef — it is added to the current StudyEventDef (calladd_study_event_def()first).- Parameters:
kwargs (Any) – ItemGroupRef attributes (ItemGroupOID, Mandatory, …).
- Returns:
self, for chaining.
- Raises:
RuntimeError – if the required parent has not been added yet.
- Return type:
- add_method_def(OID, Name, Type, description, formal_expression=None, expression_context='Python', lang='en', **kwargs)[source]
Add a MethodDef to the current MetaDataVersion.
MethodDef requires a Description; it is built from
description. An optional FormalExpression is added whenformal_expressionis given.formal_expressionis plain text for every model. Underodm_2_0it is wrapped in theCodechild the XSD requires; under ODM 1.3.2 / Define-XML it stays element text.Under
odm_2_0the XSD also makesMethodSignaturea required child of MethodDef, so an empty one is emitted for you (both of its children are optional, so<MethodSignature/>is valid); populate it viaattach()if the method takes parameters. ODM 1.3.2 adds no MethodSignature.Changed in version 0.2.1:
formal_expressionis now valid underodm_2_0, and a MethodSignature is emitted there, so the output is schema-valid.- Parameters:
OID (str) – Method OID.
Name (str) – Method name.
Type (str) – Method type (e.g. “Computation”, “Imputation”).
description (str) – Human-readable description text.
formal_expression (str | None) – Optional expression source code.
expression_context (str) – FormalExpression Context (e.g. “Python”, “SAS”); used only when
formal_expressionis given.lang (str) – Language code for the Description (default
"en").kwargs (Any) – Additional MethodDef attributes.
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no MetaDataVersion has been added yet.
- Return type:
- add_condition_def(OID, Name, description=None, formal_expression=None, expression_context='Python', lang='en', **kwargs)[source]
Add a ConditionDef to the current MetaDataVersion.
Under
odm_2_0the XSD makes bothDescriptionandMethodSignaturerequired children, sodescriptionis mandatory there and an emptyMethodSignatureis emitted for you (both of its children are optional, so<MethodSignature/>is valid). Populate it further viaattach()if the condition’s expressions take parameters. ODM 1.3.2 is unchanged:descriptionstays optional and no MethodSignature is added.formal_expressionis plain text for every model; underodm_2_0it is wrapped in aCodechild (seeadd_method_def()).Changed in version 0.2.1: Produces schema-valid output under
odm_2_0.- Parameters:
OID (str) – Condition OID.
Name (str) – Condition name.
description (str | None) – Description text. Required under
odm_2_0, optional for ODM 1.3.2.formal_expression (str | None) – Optional expression source code.
expression_context (str) – FormalExpression Context; used only when
formal_expressionis given.lang (str) – Language code for the Description (default
"en").kwargs (Any) – Additional ConditionDef attributes.
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no MetaDataVersion has been added yet, or if
descriptionis omitted underodm_2_0.- Return type:
- add_measurement_unit(OID, Name, symbol, lang='en', **kwargs)[source]
Add a MeasurementUnit to the Study’s BasicDefinitions.
BasicDefinitions is created automatically if absent. Not available in ODM 2.0 (which has no BasicDefinitions/MeasurementUnit).
- Parameters:
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no Study yet, or model is ODM 2.0.
- Return type:
- with_question(text, lang='en')[source]
Set the Question on the most recently created ItemDef.
- Parameters:
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no ItemDef has been added yet.
- Return type:
- with_codelist_ref(codelist_oid)[source]
Attach a CodeListRef to the most recently created ItemDef.
- Parameters:
codelist_oid (str) – OID of the referenced CodeList.
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no ItemDef has been added yet.
- Return type:
- with_measurement_unit_ref(mu_oid)[source]
Add a MeasurementUnitRef to the most recent ItemDef (ODM 1.3.2 only).
- Parameters:
mu_oid (str) – OID of the referenced MeasurementUnit.
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no ItemDef yet, or model is ODM 2.0.
- Return type:
- with_range_check(comparator, check_values, soft_hard='Soft', **kwargs)[source]
Add a RangeCheck to the most recently created ItemDef.
- Parameters:
- Returns:
self, for chaining.
- Raises:
RuntimeError – if no ItemDef has been added yet.
- Return type:
- with_alias(context, name)[source]
Add an Alias to the most recent ItemDef (or ItemGroupDef).
Applies to the most recently created ItemDef; falls back to the current ItemGroupDef.
- Parameters:
- Returns:
self, for chaining.
- Raises:
RuntimeError – if neither an ItemDef nor ItemGroupDef exists.
- Return type:
- attach(parent, element)[source]
Attach a pre-built ODMElement onto an explicit parent element.
Escape hatch for any model element that has no dedicated
add_*method. The target child field is resolved from the parent’s model definition — appended if it is a list element, assigned otherwise.- Parameters:
- Returns:
self, for chaining.
- Raises:
TypeError – if element is not an ODMElement or parent has no child field able to hold it.
- Return type:
- attach_to_current(element)[source]
Attach a pre-built ODMElement to the most specific current parent.
Tries the active ItemDef, FormDef, StudyEventDef, ItemGroupDef, MetaDataVersion and Study in turn, attaching to the first that accepts element’s type.
context module
Context managers for common odmlib load-modify-save workflows.
Provides open_odm() and open_define() context managers that
automatically load an ODM or Define-XML document on entry and, when a
write target is configured, write it back on clean exit.
Opening a document with only an input_file is read-only: nothing is
written when the with block exits. Provide output_file to write
the (possibly modified) document to a different path, or pass
write_on_exit=True to explicitly opt in to updating input_file
in place.
Example — read an ODM file (read-only, nothing written):
from odmlib.context import open_odm
with open_odm("study.xml") as odm:
print(odm.FileOID)
Example — modify an ODM file, write to a different path:
with open_odm("study.xml", output_file="study_updated.xml") as odm:
odm.FileOID = "F.002"
Example — update an ODM file in place (explicit opt-in):
with open_odm("study.xml", write_on_exit=True) as odm:
mdv = odm.Study[0].MetaDataVersion[0]
mdv.ItemGroupDef.append(new_igd)
# study.xml is overwritten with the modified content
Example — read a Define-XML 2.1 file:
from odmlib.context import open_define
with open_define("define.xml") as define:
# Define-XML: Study and MetaDataVersion are single objects, not lists
mdv = define.Study.MetaDataVersion
print(len(mdv.ItemDef))
- class context.ODMContext(input_file, output_file=None, model_package='odm_1_3_2', format=None, permissive=False, write_on_exit=None)[source]
Bases:
objectContext manager for load-modify-save ODM workflows.
The document is loaded when the
withblock is entered and written back tooutput_filewhen the block exits normally. If an exception propagates out of thewithblock the file is not written (the exception is re-raised unchanged).- Parameters:
input_file (str) – Path to the ODM file to load.
output_file (Optional[str]) – Path to write on clean exit. When omitted, the document is opened read-only and nothing is written (unless
write_on_exit=Trueexplicitly opts in to updatinginput_filein place).model_package (str) – odmlib model package name. Defaults to
"odm_1_3_2".format (Optional[str]) –
"xml"or"json". Auto-detected from the file extension when not specified.write_on_exit (Optional[bool]) – When omitted, the document is written on clean exit only if
output_filewas provided. PassTrueto force writing (tooutput_file, or in place toinput_filewhen nooutput_fileis given). PassFalseto suppress writing entirely.permissive (Union[bool, _mode.ValidationMode])
- class context.DefineContext(input_file, output_file=None, model_package='define_2_1', format=None, permissive=False, write_on_exit=None)[source]
Bases:
ODMContextContext manager for load-modify-save Define-XML workflows.
Identical to
ODMContextbut uses Define-XML loaders by default.- Parameters:
input_file (str) – Path to the Define-XML file to load.
output_file (Optional[str]) – Path to write on clean exit. When omitted, the document is opened read-only and nothing is written (unless
write_on_exit=Trueexplicitly opts in to updatinginput_filein place).model_package (str) – odmlib model package name. Defaults to
"define_2_1".format (Optional[str]) –
"xml"or"json".write_on_exit (Optional[bool]) – When omitted, the document is written on clean exit only if
output_filewas provided.Trueforces writing (in place when nooutput_file);Falsesuppresses writing entirely.permissive (Union[bool, _mode.ValidationMode])
- context.open_odm(input_file, output_file=None, model_package='odm_1_3_2', format=None, permissive=False, write_on_exit=None)[source]
Open an ODM document as a context manager.
- Parameters:
input_file (str) – Path to the ODM file.
output_file (str | None) – Write path on clean exit. When omitted, the document is opened read-only (nothing is written unless
write_on_exit=Trueopts in to an in-place update).model_package (str) – odmlib model package (default
"odm_1_3_2").format (str | None) –
"xml"or"json"(auto-detected if omitted).permissive (bool | ValidationMode) – If
True, load in fully permissive mode. Pass aValidationModeflag combination for targeted relaxation. Defaults toFalse(strict).write_on_exit (bool | None) – When omitted, the document is written on clean exit only if
output_filewas provided.Trueforces writing (in place when nooutput_file);Falsesuppresses writing entirely.
- Returns:
An
ODMContextinstance.- Return type:
Example:
# Read-only inspection — input file is never modified with open_odm("study.xml") as odm: print(odm.FileOID) with open_odm("broken.xml", permissive=True) as odm: ... # permissive mode active during load # Modify and write to a new file with open_odm("study.xml", output_file="study_v2.xml") as odm: odm.FileOID = "F.002" # Update the input file in place (explicit opt-in) with open_odm("study.xml", write_on_exit=True) as odm: odm.FileOID = "F.002"
- context.open_define(input_file, output_file=None, model_package='define_2_1', format=None, permissive=False, write_on_exit=None)[source]
Open a Define-XML document as a context manager.
- Parameters:
input_file (str) – Path to the Define-XML file.
output_file (str | None) – Write path on clean exit. When omitted, the document is opened read-only (nothing is written unless
write_on_exit=Trueopts in to an in-place update).model_package (str) – odmlib model package (default
"define_2_1").format (str | None) –
"xml"or"json"(auto-detected if omitted).permissive (bool | ValidationMode) – If
True, load in fully permissive mode. Pass aValidationModeflag combination for targeted relaxation. Defaults toFalse(strict).write_on_exit (bool | None) – When omitted, the document is written on clean exit only if
output_filewas provided.Trueforces writing (in place when nooutput_file);Falsesuppresses writing entirely.
- Returns:
A
DefineContextinstance.- Return type:
Example:
# Read-only inspection — input file is never modified with open_define("define.xml") as define: # Define-XML: Study/MetaDataVersion are single objects, not lists mdv = define.Study.MetaDataVersion with open_define("broken.xml", permissive=True) as define: ... # permissive mode active during load
descriptor module
Base descriptor protocol for ODM element attributes.
This module provides the Descriptor base class that implements
the Python descriptor protocol for ODM element attributes. All odmlib
attribute types inherit from this class.
- descriptor.is_pristine_auto_created(elem)[source]
True if elem was auto-created by attribute access and never populated.
Used by serialization to skip empty elements that exist only because an unset optional child attribute was read.
- class descriptor.Descriptor(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
objectBase descriptor for all ODM element attributes.
Implements the Python descriptor protocol (
__get__,__set__,__delete__). When accessed on a class, returns the descriptor itself. When accessed on an instance, returns the value from the instance’s__dict__.For required attributes without a set value, raises
OdmlibRequiredAttributeError. For optional list attributes without a value, auto-initializes to [] (stored on the instance so the append idiom works). For unset optional scalar attributes, returnsNone. For unset single child elements, auto-instantiates the element class when it can be constructed empty (returnsNoneotherwise); the auto-created child is skipped by serialization unless populated.- Parameters:
name (str) – Attribute name (set by
ODMMetaduring class creation).required (bool) – If True, attribute must be provided at construction.
element_class (type) – For child element descriptors, the expected class.
valid_values (list) – List of permitted values (empty = any value).
namespace (str) – XML namespace prefix (default: “odm”).
document_loader module
Abstract base class for all odmlib document loaders.
Defines the interface that all concrete loaders
(XMLODMLoader,
JSONODMLoader,
XMLDefineLoader,
JSONDefineLoader,
XMLArmLoader,
JSONArmLoader).
Loaders are not typically used directly; pass an instance to
ODMLoader for a unified facade.
- document_loader.resolve_model_class(model_module, elem_name)[source]
Return the model class for an element tag, or raise a clear error.
Previously an unknown element in a document surfaced as a bare
AttributeErrorfromgetattrdeep inside the recursive load.- Parameters:
model_module – The imported model module (e.g. odmlib.odm_1_3_2.model).
elem_name – The element tag / dict key naming the class.
- Raises:
OdmlibParsingError – If the model has no class for
elem_name.
- class document_loader.DocumentLoader[source]
Bases:
ABCAbstract base class for odmlib document loaders.
All concrete loaders implement this interface so they can be wrapped by the
ODMLoaderfacade.- abstractmethod load_document(doc)[source]
Recursively load a parsed document element or dict into odmlib objects.
- Parameters:
doc – An XML
Element(XML loaders) ordict(JSON loaders).- Returns:
An odmlib element object populated from
doc.
- abstractmethod create_document(filename)[source]
Parse a document file and store its contents internally.
- Parameters:
filename (str) – Path to the ODM file (XML or JSON).
- Returns:
The parsed root element or dict.
- abstractmethod create_document_from_string(odm_string)[source]
Parse a document string and store its contents internally.
- Parameters:
odm_string (str) – XML or JSON string containing the ODM document.
- Returns:
The parsed root element or dict.
- abstractmethod load_metadataversion(idx)[source]
Return the MetaDataVersion at the given index.
- Parameters:
idx (int) – Zero-based index of the MetaDataVersion to return.
- Returns:
A
MetaDataVersionodmlib object.
exceptions module
odmlib exception hierarchy.
All odmlib-specific exceptions inherit from OdmlibError, which itself inherits from Exception. During the v0.2.x transition period, validation and type exceptions also inherit from ValueError/TypeError respectively so that existing except clauses continue to work.
- Deprecation schedule:
- v0.2.x: New exceptions dual-inherit from ValueError/TypeError.
All existing
except ValueErrorandexcept TypeErrorclauses continue to work unchanged.- v0.3.0: Remove the ValueError/TypeError base classes.
Update
except ValueError→except OdmlibValidationErrorandexcept TypeError→except OdmlibTypeError.
- exception exceptions.OdmlibValidationError(message, *, element_path=None, hint=None, attribute=None, element_type=None, actual_value=None)[source]
Bases:
OdmlibError,ValueErrorRaised when an element fails conformance, OID, or schema validation.
- element_path
Dot-separated path from root to the failing element, e.g. “ODM > Study > MetaDataVersion > ItemGroupDef(OID=’IG.VS’)”
- hint
Optional human-readable suggestion for fixing the problem.
- attribute
The attribute name that caused the error (if applicable).
- element_type
The class name of the element that failed validation.
- exception exceptions.OdmlibRequiredAttributeError(message, *, element_path=None, hint=None, attribute=None, element_type=None, actual_value=None)[source]
Bases:
OdmlibValidationErrorRaised when a required attribute is missing during construction.
- exception exceptions.OdmlibOIDError(message, *, element_path=None, hint=None, attribute=None, element_type=None, actual_value=None)[source]
Bases:
OdmlibValidationErrorRaised for OID uniqueness or ref/def integrity failures.
- exceptions.flatten_cerberus_errors(errors, prefix='')[source]
Flatten a nested Cerberus error dict into
(dotted_path, message)pairs.Cerberus reports
{field: [msg | {subkey: [...]}, ...]}where subkey is a nested field name or, for sequences, the integer index of the offending list item:{'ItemGroupDef': [{0: [{'Name': ['required field']}]}]} -> [('ItemGroupDef.0.Name', 'required field')]
- Parameters:
errors – A Cerberus error dict (typically
OdmlibConformanceError.cerberus_errors). Anything that is not a dict yields an empty list.prefix – Dotted path accumulated so far; used by the recursion.
- Returns:
(path, message)tuples in Cerberus’ own document order, which is deterministic — no sets are involved.- Return type:
- exception exceptions.OdmlibConformanceError(message, *, cerberus_errors=None, field_path=None, **kwargs)[source]
Bases:
OdmlibValidationErrorRaised when Cerberus conformance validation fails.
A single instance normally bundles every violation Cerberus found, so
validate()callsexpand()in collect mode to turn it into one error per failing field.- cerberus_errors
The raw Cerberus error dict for programmatic access. On errors produced by
expand()this remains the complete dict for the document, shared by reference with its siblings.
- field_path
Dotted path to the single failing field (e.g.
"ItemGroupDef.0.Name"). Set only on errors produced byexpand();Noneon the bundled error.
- expand()[source]
Split this bundled error into one error per failing leaf field.
- Returns:
One
OdmlibConformanceErrorper Cerberus leaf message, each carryingfield_path,attribute(the leaf name) andelement_path(the containing path). Returns[self]when there is no Cerberus payload to split — e.g. the “No conformance schema registered” error — so nothing is lost.- Return type:
- exception exceptions.OdmlibElementOrderError(message, *, element_path=None, hint=None, attribute=None, element_type=None, actual_value=None)[source]
Bases:
OdmlibValidationErrorRaised when child elements are not in the order required by the ODM spec.
- exception exceptions.OdmlibErrorLimitError(message, *, element_path=None, hint=None, attribute=None, element_type=None, actual_value=None)[source]
Bases:
OdmlibValidationErrorAppended as the final entry when
validate(max_errors=N)stops early.Its presence means validation was truncated and additional problems may exist. It is never raised — only collected.
- exception exceptions.OdmlibSchemaValidationError(wrapped_exception, *, hint=None)[source]
Bases:
OdmlibValidationErrorRaised when XSD/XML-Schema validation of an ODM document fails.
Wraps the underlying
xmlschemaexception raised during XSD validation (e.g. byODMSchemaValidator.validate_file()). The wrapped exception is available atargs[0](for backward compatibility with callers that introspectex.args[0].msg) and via thewrappedattribute.
- exception exceptions.OdmlibTypeError(message, *, attribute=None, expected_type=None, actual_value=None, element_path=None, hint=None, element_type=None)[source]
Bases:
OdmlibError,TypeErrorRaised when a value has the wrong type for an attribute.
- attribute
The attribute name.
- expected_type
The expected type description.
- actual_value
The value that was provided.
- element_path
Path from root to the failing element (if known).
- hint
Optional human-readable suggestion for fixing the problem.
- exception exceptions.OdmlibParsingError(message, *, hint=None)[source]
Bases:
OdmlibErrorRaised when an XML or JSON document cannot be parsed into the model.
- exception exceptions.OdmlibLoaderStateError(message, *, hint=None)[source]
Bases:
OdmlibParsingError,ValueErrorRaised when a loader method is called before the document is opened.
Also inherits from ValueError for backward compatibility with code that catches ValueError from loader calls.
- exception exceptions.OdmlibSerializationError[source]
Bases:
OdmlibErrorRaised when an in-memory model cannot be written to XML or JSON.
- exception exceptions.OdmlibNamespaceError(message, *, hint=None)[source]
Bases:
OdmlibError,ValueErrorRaised for namespace registration or lookup failures.
- exception exceptions.OdmlibWarning[source]
Bases:
UserWarningBase warning for all odmlib non-fatal issues.
- exception exceptions.OdmlibDeprecationWarning[source]
Bases:
OdmlibWarning,DeprecationWarningIssued when a deprecated odmlib feature is used.
- exception exceptions.OdmlibInteroperabilityWarning[source]
Bases:
OdmlibWarningIssued for constructs that are valid but may cause interoperability issues.
- class exceptions.ErrorCollector(max_errors=None)[source]
Bases:
objectAccumulates validation errors instead of raising immediately.
Also serves as the sink for the collecting-checker protocol: a checker that mixes in
ErrorReportinghands its errors here instead of raising, so one pass surfaces every problem it can find.Example:
errors = odm.validate(collect_errors=True, oid_checker=checker) for err in errors: print(err)
- Parameters:
max_errors – Optional cap. Once this many errors are collected, the next
add_error()setstruncatedand raises the internal_ErrorLimitReachedsentinel to unwind the in-progress validation walk.None(the default) collects everything and never raises, so hand-builtErrorCollector()instances behave exactly as before.
- errors
List of
OdmlibErrorinstances collected so far.
- warnings
List of
OdmlibWarninginstances collected so far.
- max_errors
The cap, or
Nonefor uncapped.
- truncated
True once the cap stopped collection short.
- property has_errors
True if any errors have been collected.
- property is_full
True when
max_errorsis set and that many errors are collected.
- add_error(error)[source]
Add an
OdmlibErrorto the collection.- Raises:
_ErrorLimitReached – If the collector is already at
max_errors. Never raised whenmax_errorsisNone.
- add_warning(warning)[source]
Add an
OdmlibWarningto the collection.
- raise_if_errors()[source]
Raise if any errors were collected.
Raises the single collected error directly if only one exists, or a new
OdmlibValidationErrorsummarising all errors otherwise.
- class exceptions.ErrorReporting[source]
Bases:
objectMixin giving a validation checker an optional error sink.
A checker that mixes this in replaces
raise SomeOdmlibError(...)withself.report(SomeOdmlibError(...)). With no sink installed (the default)report()re-raises, so fail-fast behaviour is identical to raising directly. Inside acollecting()block the error is handed to the sink and the checker keeps going, so a single pass surfaces every problem rather than only the first.Third-party checkers may opt in by inheriting this mixin, or by duck-typing
supports_error_collection = Trueplusreport()andcollecting(). Checkers that do neither still work — they simply contribute at most one error, exactly as before (seeis_collecting_checker()).Note
Not thread-safe: the sink lives on the instance. Checkers are already stateful (they accumulate OIDs), so use one checker per document per thread.
- supports_error_collection = True
- report(error)[source]
Raise error (fail-fast) or hand it to the installed sink.
- Parameters:
error – The
OdmlibErrordescribing the problem.- Raises:
OdmlibError – The error itself, when no sink is installed.
_ErrorLimitReached – When the sink is full (see
ErrorCollector).
- collecting(sink)[source]
Install sink for the duration of the block, then restore.
- Parameters:
sink – Any object with an
add_error(error)method — normally anErrorCollector.
Example:
collector = ErrorCollector() with checker.collecting(collector): odm.verify_oids(checker) for err in collector.errors: print(err)
- exceptions.is_collecting_checker(checker)[source]
Return True if checker implements the collecting-checker protocol.
Used by
validate()to decide whether a checker can enumerate every problem or should fall back to fail-fast (one error for the whole layer). Duck-typed checkers qualify without inheritingErrorReporting.
loader module
Facade loader for ODM, Define-XML, and ARM documents.
This module provides ODMLoader, a unified interface that wraps
any specialized loader (XMLODMLoader,
JSONODMLoader,
XMLDefineLoader,
JSONDefineLoader,
XMLArmLoader, or
JSONArmLoader) and delegates all
document loading operations to it.
- class loader.ODMLoader(odm_loader)[source]
Bases:
objectFacade providing a unified interface for loading ODM documents.
Wraps a specialized loader (
XMLODMLoader,JSONODMLoader,XMLDefineLoader,JSONDefineLoader,XMLArmLoader, orJSONArmLoader) and delegates all operations to it.- Parameters:
odm_loader (DocumentLoader) – A specialized loader instance.
- Raises:
OdmlibTypeError – If
odm_loaderis not a DocumentLoader instance.
Example:
import odmlib.odm_loader as OL import odmlib.loader as LD loader = LD.ODMLoader(OL.XMLODMLoader(model_package="odm_1_3_2")) loader.open_odm_document("study.xml") odm = loader.root() mdv = loader.MetaDataVersion()
- create_odmlib(odm_doc, odm_key=None)[source]
Load an odmlib object from an existing document dict or element.
Delegates to the wrapped loader’s
load_documentmethod.
- root()[source]
Return the root ODM element.
Must be called after
open_odm_document()orload_odm_string().- Returns:
The root odmlib ODM object (e.g., an
ODMinstance).- Return type:
- MetaDataVersion(idx=0)[source]
Return the MetaDataVersion at the specified index.
Must be called after
open_odm_document()orload_odm_string().
- Study(idx=0)[source]
Return the Study at the specified index.
Must be called after
open_odm_document()orload_odm_string().
ns_registry module
Global registry for XML namespace prefix-to-URI mappings.
This module provides Borg and NamespaceRegistry for
managing XML namespace declarations used in ODM and Define-XML documents.
The Borg pattern ensures that all instances of NamespaceRegistry
share the same state, providing a convenient global registry without
requiring a strict singleton or global variable.
Example:
import odmlib.ns_registry as NS
NS.NamespaceRegistry(prefix="odm",
uri="http://www.cdisc.org/ns/odm/v1.3",
is_default=True, is_reset=True)
NS.NamespaceRegistry(prefix="def",
uri="http://www.cdisc.org/ns/def/v2.1")
- ns_registry.bind_document_namespaces(odm_obj, snapshot=None, recursive=False)[source]
Associate odm_obj with a namespace snapshot for serialization.
- Parameters:
odm_obj – A loaded odmlib element (typically the document root).
snapshot – A dict as returned by
NamespaceRegistry.snapshot(). WhenNone, the registry’s current state is captured.recursive – When True, also bind every descendant element, so that serializing a child reached by walking the tree (
define.Study.MetaDataVersion) uses the same namespaces as its root instead of falling back to current global registry state.
- ns_registry.get_document_namespaces(odm_obj)[source]
Return the namespace snapshot bound to odm_obj, or
None.
- class ns_registry.Borg[source]
Bases:
objectBorg pattern base class providing shared state across instances.
All instances of subclasses share the same
namespacesanddefault_namespacedictionaries, enabling a singleton-like namespace registry without requiring a true singleton.- Class Attributes:
namespaces (dict): Maps prefix to URI for all registered namespaces. default_namespace (dict): Maps the default namespace prefix to URI.
- namespaces = {}
- default_namespace = {}
- class ns_registry.NamespaceRegistry(prefix=None, uri=None, is_default=False, is_reset=False)[source]
Bases:
BorgGlobal registry for XML namespace prefix-to-URI mappings.
Uses the Borg pattern so all instances share state. Manages namespace prefix registration and provides methods for XML serialization.
- Parameters:
- Raises:
OdmlibNamespaceError – If the URI is not a valid URL.
Example:
import odmlib.ns_registry as NS NS.NamespaceRegistry(prefix="odm", uri="http://www.cdisc.org/ns/odm/v1.3", is_default=True, is_reset=True)
- snapshot()[source]
Return a copy of the current registry state.
- Returns:
{"namespaces": {prefix: uri, ...}, "default": {prefix: uri}}.- Return type:
- get_odm_namespace_entries()[source]
Return namespace entries as xmlns= strings for XML serialization.
- get_ns_entry_dict(prefix)[source]
Return a
{prefix: uri}dict for the given prefix, or{}if not found.Used by loaders to build the
namespacesdict for ElementTreefindandfindallcalls.
- get_ns_attribute_name(name, prefix)[source]
Return the full ElementTree-style attribute name with namespace braces.
For the default namespace, returns the bare
name. For non-default namespaces, returns{uri}name.- Parameters:
- Returns:
- The qualified attribute name (e.g.,
"{http://...}lang" or
"lang"for the default namespace).
- The qualified attribute name (e.g.,
- Return type:
- Raises:
OdmlibNamespaceError – If
prefixhas not been registered.
- get_prefix_ns_from_uri(uri)[source]
Return the prefix for a given namespace URI.
- Parameters:
uri (str) – The namespace URI to look up (case-insensitive match).
- Returns:
The registered prefix for that URI.
- Return type:
- Raises:
OdmlibNamespaceError – If no prefix is registered for
uri.
- set_odm_namespace_attributes(odm_elem, namespaces=None, default=None)[source]
Set xmlns attributes on an ElementTree root element.
Adds
xmlnsfor the default namespace andxmlns:prefixfor each additional namespace that is actually used in the tree. The reservedxmlprefix is never declared (it is implicitly bound per the XML specification).- Parameters:
- Raises:
OdmlibNamespaceError – If no default namespace is registered.
- set_odm_namespace_attributes_string(odm_str)[source]
Add xmlns attributes to an ODM XML string.
Deprecated since version 0.2.1:
ODMElement.to_xml_string()has declared its own namespaces since 0.2.1, so this string-patching helper is a no-op on any string it would normally be handed. It has no callers in odmlib and will be removed in 0.3.0. Remove the call; no replacement is needed.Replaces the opening
<ODMtag inodm_strwith a version that includes all registered namespace declarations.
odm_element module
Core metaclass, writer, and base element class for odmlib ODM models.
This module provides three central components:
ODMMeta– metaclass that processes descriptor-based class definitionsODMWriter– utility class for writing ElementTree XML to fileODMElement– base class for all ODM element model objects
All model classes (e.g., Study, ItemDef, MetaDataVersion) inherit
from ODMElement and use descriptors from odmlib.typed to define
their attributes and child elements.
- class odm_element.ODMMeta(clsname, bases, clsdict, merge_fields=False)[source]
Bases:
typeMetaclass for all ODM element classes.
Processes class definitions to:
Preserve attribute declaration order (using OrderedDict)
Separate XML attributes (
_attrs) from child elements (_elems)Track non-default namespace prefixes (
_attr_ns)Build the
_fieldslist of all declared propertiesSet the default
namespaceto “odm” if not specified
- class odm_element.ODMWriter[source]
Bases:
objectWrites an odmlib ElementTree hierarchy to an XML file.
Handles namespace registration and XML declaration.
- static write_odm(odm_file, odm_elem, ns_snapshot=None)[source]
after converting ODMLIB to ElementTree, write the ElementTree to an ODM file :param odm_file: path and file to write the ODM XML :param odm_elem: Element object to write to ODM (presumably an ODM root) :param ns_snapshot: optional per-document namespace snapshot (as returned
by NamespaceRegistry.snapshot()); when omitted, the shared registry state is used
- class odm_element.ODMElement(**kwargs)[source]
Bases:
objectBase class for all ODM element model objects.
Provides XML and JSON serialization, OID validation, conformance checking, and element ordering verification. All model classes (e.g., Study, ItemDef, MetaDataVersion) inherit from this class.
- Serialization:
to_xml_string()– XML as a string (self-contained; declares its own xmlns)to_element()– namespace-resolved ElementTree Elementto_dict()– Python dict (namespace info stripped)to_json()– JSON stringwrite_xml()– write XML to filewrite_json()– write JSON to fileto_xml()– internal tree builder; no xmlns (preferto_element())
- Validation:
verify_oids()– OID uniqueness and ref/def integrityverify_conformance()– Cerberus schema conformanceverify_order()– element order per ODM specvalidate()– combined validation with error collection
- Finding elements:
find()– find first child element by attribute valuefind_all()– find all matching child elementsfind_by()– find by multiple attribute criteria
- Parameters:
kwargs (Any)
- __init__(**kwargs)[source]
Initialize an ODM element with keyword arguments.
Sets attributes and child elements on the instance using the provided keyword arguments. Validates that all required attributes are present after construction.
- Parameters:
**kwargs (Any) – Attribute names and values for this element. Names must match declared descriptors on the class.
- Raises:
OdmlibTypeError – If an unknown keyword argument is provided.
OdmlibRequiredAttributeError – If a required attribute is missing.
- Return type:
None
- to_json()[source]
transforms odmlib hierarchy into a dict and converts that to JSON and returns it
- Returns:
JSON representation of odmlib hierarchy
- Return type:
- to_xml(parent_elem=None, top_elem=None)[source]
Build odmlib’s internal ElementTree serialization buffer.
Prefer :meth:`to_element` if you want a tree to work with. The Element returned here carries no xmlns declarations and uses prefix-literal tags (
def:leaf) rather than Clark notation, so on its own it cannot be re-parsed for Define-XML (ParseError: unbound prefix), lands in no namespace for ODM, failsET.canonicalize(), and does not support namespace-awarefind(). Declarations are attached downstream byto_xml_string()andODMWriter. This method exists as the shared tree builder for those two.Children are emitted in the model declaration order recorded in
_elemsbyODMMeta(i.e. the order in which descriptors appear in the class body of the relevant model module). Attribute insertion order on the instance does not affect the output, so users do not need to callreorder_object()before serializing.Optional children that were never assigned are silently skipped.
- to_xml_string(*, xml_declaration=False)[source]
Convert this element to an XML string.
The string includes xmlns declarations for the default namespace and any prefixes used in the serialized tree, so the result is namespace-well-formed and can be re-parsed on its own.
The two serialization paths line up exactly, which makes a string and a file interchangeable for comparison purposes:
xml_declaration=False(the default) returns precisely the byteswrite_xml()produces after its<?xml ...?>line.xml_declaration=Truereturns precisely whatwrite_xml()writes, declaration included.
The default stays
False: this string is the documented input toODMLoader.load_odm_string(), and 0.2.1 shipped it declaration-free.
- to_element()[source]
Return this element as a standard, namespace-resolved ElementTree Element.
Unlike
to_xml(), which builds odmlib’s internal serialization buffer with prefix-literal tags (def:leaf) and no declarations, this returns a tree parsed fromto_xml_string(). Tags and attributes use Clark notation ({http://www.cdisc.org/ns/def/v2.1}leaf), so namespace-awarefind(),ET.canonicalize(),ET.indent()pretty-printing, and grafting the result into a host document you are assembling yourself all behave correctly.This is the method to reach for when you want an
Element;to_xml()is the internal tree builder and its output is not a self-contained document.Costs one serialize + reparse (~8 ms for a 166 KB Define-XML document).
Note that re-serializing the result with
ET.tostring()picks prefixes from ElementTree’s process-globalregister_namespace()map, so the prefix spelling may differ from the source document (odm:ODMrather than a defaultxmlns). The namespaces themselves are identical. Useto_xml_string()orwrite_xml()when you need odmlib’s exact output.- Returns:
a namespace-resolved
ET.Element- Raises:
OdmlibNamespaceError – if no default namespace is registered
- Return type:
- to_dict()[source]
transform odmlib object hierarchy into a Python dictionary and return it
- Returns:
dictionary serialization of odmlib hierarchy
- Return type:
- find(obj_name, attr, val)[source]
Return the first odmlib object where attribute
attrequalsval.Searches within the child element(s) named
obj_nameon this element. For list elements (ODMListObject), returns the first match. For single elements (ODMObject), returns the element if it matches.- Parameters:
- Returns:
first matching odmlib object, or None if not found
- Return type:
ODMElement | None
- find_all(obj_name, attr, val)[source]
Return all odmlib objects where attribute
attrequalsval.Like find(), but returns all matches instead of just the first.
- Parameters:
- Returns:
list of matching odmlib objects (empty list if no matches)
- Return type:
- find_by(obj_name, **kwargs)[source]
Return the first odmlib object matching all keyword criteria.
A more ergonomic alternative to find() for multi-attribute lookups.
- Parameters:
- Returns:
first matching odmlib object, or None
- Return type:
ODMElement | None
- write_xml(odm_file, odm_writer=<class 'odm_element.ODMWriter'>)[source]
write the odmlib hierarchy as an XML file
- write_json(odm_file)[source]
write the odmlib hierarchy as a JSON file
- Parameters:
odm_file (str) – string ODM filename and path
- Return type:
None
- build_oid_index()[source]
Build an OID lookup index for this element and all descendants.
Traverses the entire object tree and creates an index mapping OID attribute values to their containing odmlib objects.
- Returns:
Index supporting
find_all(oid)lookups.- Return type:
- verify_oids(oid_checker)[source]
checks all the OIDs for uniqueness and Def/Ref integrity; oid_checker throws a ValueError on failure
- unreferenced_oids(oid_checker)[source]
Find OID definitions that are not referenced anywhere.
Calls
verify_oids()first if OIDs have not yet been verified.- Parameters:
oid_checker (Any) – An
OIDRefinstance (fromrules/oid_ref.py) or aDynamicOIDRefinstance.- Returns:
Mapping of
oid_value -> ref_attr_namefor each OID that is defined but never referenced. An empty dict means every definition is used.- Return type:
Note
Pass a checker that has been through a collect-mode
validate()(or an otherwise completeverify_oids()). After a fail-fastverify_oids()that raised, the checker is only half-populated and this method can report a misleading duplicate naming an OID that is not in fact duplicated.
- verify_conformance(validator)[source]
uses validator object to check object for conformance with the model
- verify_order()[source]
Verify that child elements are in the model declaration order.
Recursively checks this element and all descendants — calling at the odmlib root covers the whole document. Works on any
ODMElementsubclass; not applicable toxml.etree.ElementTree.Element(load through a loader first if you only have an ElementTree).Limitations:
Each class’s expected order comes from descriptors declared in its own class body. Custom extensions that subclass a model class must redeclare base children in schema order — otherwise inherited children are flagged as unexpected.
In permissive mode (
SKIP_TYPE) unknown attributes can land in__dict__; they will trip this check until cleaned up.Only the order of different child element kinds is checked. Order within a single list (e.g. multiple
ItemRefentries) is not validated — ODM relies onOrderNumberattributes for that.Completeness is not checked. Missing required children must be caught via
verify_conformance()orvalidate().
Note
to_xml()/write_xml()already emit children in_elemsorder, soverify_order()is not required before XML serialization. It is still useful beforeto_dict()/to_json(), which walk__dict__and therefore reflect instance assignment order.- Returns:
True if ordering is correct.
- Return type:
- Raises:
OdmlibElementOrderError – If any element has children out of order. Use
reorder_object()to fix automatically.
See also
validate()withcollect_errors=Truereports every misordered element in one pass instead of just the first.
- reorder_object()[source]
Reorder this element’s children to match model declaration order.
Modifies
__dict__in-place. Issues anOdmlibWarningto indicate that reordering was needed.Note
Recursion is not automatic — call on each element that needs reordering, or call
verify_order()first to identify which elements need reordering.- Return type:
None
- validate(collect_errors=False, oid_checker=None, conformance_checker=None, max_errors=None)[source]
Validate this element and all children.
Runs up to three layers: element order, OID uniqueness and ref/def integrity, and Cerberus conformance. In collect mode each layer enumerates every problem it can find rather than stopping at its first.
- Parameters:
collect_errors – If True, accumulate every error each layer can find and return them as a list instead of raising on the first failure. Defaults to False (fail-fast, existing behaviour).
oid_checker – Optional OID checker — a
DynamicOIDReffromcreate_oid_checker(), or a deprecatedrules.oid_ref.OIDRef. Checkers that do not implement the collecting protocol (seeis_collecting_checker()) still work, but contribute at most one error to the list.conformance_checker – Optional
MetadataSchemainstance. In collect mode the bundled Cerberus result is expanded into one error per failing field; in fail-fast mode the single bundledOdmlibConformanceErroris raised unchanged.max_errors – Optional cap on collected errors. Collection stops the moment the cap is reached and a final
OdmlibErrorLimitErroris appended, so the list holds at mostmax_errors + 1entries.None(the default) collects everything. Ignored whencollect_errorsis False.max_errors=0checks nothing and returns just the limit marker.
- Returns:
True(or raises on first error). Ifcollect_errors=True: list ofOdmlibErrorinstances (an empty list means valid).- Return type:
If
collect_errors=False
Note
OID checkers are stateful. Use one checker instance per document, or call
reset()on aDynamicOIDRefbetween runs — otherwise the second pass reports every OID as a duplicate.Only
OdmlibErrorsubclasses are collected. Any other exception (a bug in a custom checker, anAttributeErrorfrom a malformed permissively-loaded tree) propagates in both modes. Note thatOdmlibTypeErroris anOdmlibErrorand is therefore collected.Example:
errors = odm.validate(collect_errors=True, oid_checker=checker, max_errors=100) for err in errors: print(err)
Changed in version 0.2.1: Each layer now reports every problem it finds. Previously
collect_errors=Truereturned at most one error per layer (three in total), solen(errors)may be larger than before. Addedmax_errors.
- namespace = 'odm'
odm_loader module
Concrete loaders for standard ODM XML and JSON documents.
This module provides:
JSONODMLoader– loads ODM-JSON files into the odmlib object modelDictODMLoader– alias for JSONODMLoader (loads from Python dicts)XMLODMLoader– loads ODM-XML files into the odmlib object model
These loaders are typically used via the ODMLoader
facade rather than directly.
- class odm_loader.JSONODMLoader(model_package='odm_1_3_2')[source]
Bases:
DocumentLoaderLoads ODM-JSON documents into the odmlib object model.
Recursively parses JSON dictionaries and instantiates odmlib model classes based on dictionary keys matching class names.
- Parameters:
model_package (str) – Package name to load models from (default: “odm_1_3_2”). Options: “odm_1_3_2”, “odm_2_0”, “dataset_1_0_1”, “ct_1_1_1”.
- load_document(odm_dict, key)[source]
Recursively load a dict into an odmlib object tree.
Instantiates the odmlib class named
keywith scalar attributes fromodm_dict, then recurses into nested dicts (ODMObject) and lists of dicts (ODMListObject).
- create_document_from_string(odm_string)[source]
Parse an ODM JSON string and store its contents internally.
- load_odm()[source]
Return the root ODM object loaded from the stored document.
Must be called after
create_document()orcreate_document_from_string().- Returns:
An odmlib
ODMroot object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet.
- Return type:
- load_metadataversion(idx=0)[source]
Return the MetaDataVersion at index
idxfrom the stored document.Must be called after
create_document()orcreate_document_from_string().- Parameters:
idx (int) – Zero-based index of the MetaDataVersion (default: 0).
- Returns:
A
MetaDataVersionodmlib object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet.
- Return type:
- load_study(idx=0)[source]
Return the Study at index
idxfrom the stored document.Must be called after
create_document()orcreate_document_from_string().- Parameters:
idx (int) – Zero-based index of the Study (default: 0).
- Returns:
A
Studyodmlib object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet.
- Return type:
- class odm_loader.DictODMLoader(model_package='odm_1_3_2')[source]
Bases:
JSONODMLoaderLoads odmlib objects from Python dictionaries (same as JSONODMLoader).
- Parameters:
model_package (str)
- class odm_loader.XMLODMLoader(model_package='odm_1_3_2', ns_uri=None, local_model=False, nsr=None)[source]
Bases:
DocumentLoaderLoads ODM-XML documents into the odmlib object model.
Parses XML using ElementTree and dynamically instantiates odmlib model classes based on element tag names.
- Parameters:
model_package (str) – Package name (default:
"odm_1_3_2"). Options:"odm_1_3_2","odm_2_0","dataset_1_0_1","ct_1_1_1".ns_uri (Optional[str]) – ODM default namespace URI. When
None(the default), the URI is derived frommodel_package(odm_1_3_2->.../v1.3,odm_2_0->.../v2.0; other packages fall back to.../v1.3). Passing an explicit value overrides the derived default and is preserved as-is, which is useful for custom extensions or non-standard schema variants.local_model (bool) – If True,
model_packageis a full module path.nsr (Optional[Any]) – Optional pre-configured NamespaceRegistry instance.
- load_document(elem, *args)[source]
Recursively load an XML element into an odmlib object tree.
Strips the namespace URI from the tag name, instantiates the matching odmlib class, and recurses into child elements.
- Parameters:
elem (ET.Element) – The XML element to load.
*args – Unused; present for interface compatibility.
- Returns:
An odmlib element object populated from
elem.- Return type:
- create_document(filename, namespace_registry=None)[source]
Parse an ODM XML file and store the parsed tree internally.
- create_document_from_string(odm_string, namespace_registry=None)[source]
Parse an ODM XML string and store the parsed tree internally.
- load_odm()[source]
Return the root ODM object loaded from the stored document.
Must be called after
create_document()orcreate_document_from_string().- Returns:
An odmlib
ODMroot object.- Return type:
- load_metadataversion(idx=0)[source]
Return the MetaDataVersion at index
idxfrom the stored document.Must be called after
create_document()orcreate_document_from_string().
- load_study(idx=0)[source]
Return the Study at index
idxfrom the stored document.Must be called after
create_document()orcreate_document_from_string().
define_loader module
Concrete loaders for Define-XML documents (XML and JSON formats).
This module provides:
XMLDefineLoader– loads Define-XML files into the odmlib object modelJSONDefineLoader– loads Define-XML JSON files into the odmlib object model
These loaders handle Define-XML extensions including the def: namespace
and additional elements like ValueListDef, WhereClauseDef, and CommentDef.
They are typically used via the ODMLoader facade.
- class define_loader.XMLDefineLoader(model_package='define_2_0', ns_uri=None, local_model=False)[source]
Bases:
DocumentLoaderLoads Define-XML documents into the odmlib object model.
Handles Define-XML extensions including the
def:namespace and additional elements like ValueListDef, WhereClauseDef, and CommentDef.- Parameters:
model_package (str) – Package name (default:
"define_2_0"). Options:"define_2_0","define_2_1".ns_uri (Optional[str]) – Define-XML
def:namespace URI. WhenNone(the default), the URI is derived frommodel_package(define_2_0->.../v2.0,define_2_1->.../v2.1). Passing an explicit value overrides the derived default and is preserved as-is, which is useful for custom extensions or non-standard schema variants.local_model (bool) – If True,
model_packageis a full module path.
- load_document(elem, *args)[source]
Recursively load an XML element into an odmlib object tree.
Strips the namespace URI from the tag name, instantiates the matching odmlib class from the Define-XML model package, and recurses into child elements.
- Parameters:
elem (ET.Element) – The XML element to load.
*args – Unused; present for interface compatibility.
- Returns:
An odmlib element object populated from
elem.- Return type:
- create_document(filename, namespace_registry=None)[source]
Parse a Define-XML file and store the parsed tree internally.
- create_document_from_string(odm_string, namespace_registry=None)[source]
Parse a Define-XML string and store the parsed tree internally.
- load_odm()[source]
Return the root ODM object loaded from the stored document.
Must be called after
create_document()orcreate_document_from_string().- Returns:
An odmlib
ODMroot object.- Return type:
- load_metadataversion(idx=0)[source]
Return the MetaDataVersion at index
idxfrom the stored document.Must be called after
create_document()orcreate_document_from_string().
- load_study(idx=0)[source]
Return the Study from the stored document.
Must be called after
create_document()orcreate_document_from_string().Note
Define-XML documents contain a single Study element; the
idxparameter is accepted for interface compatibility but always returns index 0.
- class define_loader.JSONDefineLoader(model_package='define_2_0')[source]
Bases:
DocumentLoaderLoads Define-XML JSON documents into the odmlib object model.
- Parameters:
model_package (str) – Package name (default: “define_2_0”). Options: “define_2_0”, “define_2_1”.
- load_document(odm_dict, key)[source]
Recursively load a dict into an odmlib object tree.
Instantiates the odmlib class named
keywith scalar attributes fromodm_dict, then recurses into nested dicts (ODMObject) and lists of dicts (ODMListObject).
- create_document_from_string(odm_string)[source]
Parse a Define-XML JSON string and store its contents internally.
- load_odm()[source]
Return the root ODM object loaded from the stored document.
Must be called after
create_document()orcreate_document_from_string().- Returns:
An odmlib
ODMroot object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet.
- Return type:
- load_metadataversion(idx=0)[source]
Return the MetaDataVersion from the stored document.
Handles both flat Define-XML JSON (MetaDataVersion at root level) and nested formats (MetaDataVersion inside Study).
Must be called after
create_document()orcreate_document_from_string().- Parameters:
idx (int) – Unused; present for interface compatibility.
- Returns:
A
MetaDataVersionodmlib object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet, or if MetaDataVersion is not found in the document.
- Return type:
- load_study(idx=0)[source]
Return the Study from the stored document.
Must be called after
create_document()orcreate_document_from_string().- Parameters:
idx (int) – Unused; present for interface compatibility.
- Returns:
A
Studyodmlib object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet, or if Study is not found in the document.
- Return type:
arm_loader module
Concrete loaders for ARM (Analysis Results Metadata) documents (XML and JSON).
This module provides:
XMLArmLoader– loads ARM-extended Define-XML files into the odmlib object modelJSONArmLoader– loads ARM-extended Define-XML JSON files into the odmlib object model
ARM extends Define-XML 2.1 with elements for describing analysis results,
displays, programming code, and analysis datasets. The loaders handle the
ARM-specific elements and are typically used via the
ODMLoader facade.
Example (XML):
import odmlib.arm_loader as AL
import odmlib.loader as LD
loader = LD.ODMLoader(AL.XMLArmLoader())
loader.open_odm_document("define-adam.xml")
odm = loader.root()
Example (JSON):
import odmlib.arm_loader as AL
import odmlib.loader as LD
loader = LD.ODMLoader(AL.JSONArmLoader())
loader.open_odm_document("define-adam.json")
odm = loader.root()
- class arm_loader.XMLArmLoader(model_package='arm_1_0', ns_uri='http://www.cdisc.org/ns/arm/v1.0', local_model=False)[source]
Bases:
DocumentLoaderLoads ARM-extended Define-XML documents into the odmlib object model.
Handles the
arm:namespace and ARM-specific elements such as AnalysisResultDisplays, ResultDisplay, AnalysisResult, ProgrammingCode, and AnalysisDatasets.- Parameters:
model_package (str) – Package name (default: “arm_1_0”).
ns_uri (str) – ARM namespace URI (default: “http://www.cdisc.org/ns/arm/v1.0”).
local_model (bool) – If True,
model_packageis a full module path.
- load_document(elem, *args)[source]
Recursively load an XML element into an odmlib object tree.
Strips the namespace URI from the tag name, instantiates the matching odmlib class from the ARM model package, and recurses into child elements.
- Parameters:
elem (ET.Element) – The XML element to load.
*args – Unused; present for interface compatibility.
- Returns:
An odmlib element object populated from
elem.- Return type:
- create_document(filename, namespace_registry=None)[source]
Parse an ARM-extended Define-XML file and store the parsed tree.
- create_document_from_string(odm_string, namespace_registry=None)[source]
Parse an ARM-extended Define-XML string and store the parsed tree.
- load_odm()[source]
Return the root ODM object loaded from the stored document.
Must be called after
create_document()orcreate_document_from_string().- Returns:
An odmlib
ODMroot object.- Return type:
- load_metadataversion(idx=0)[source]
Return the MetaDataVersion at index
idxfrom the stored document.Must be called after
create_document()orcreate_document_from_string().
- load_study(idx=0)[source]
Return the Study from the stored document.
Must be called after
create_document()orcreate_document_from_string().Note
ARM documents (like Define-XML) contain a single Study element; the
idxparameter is accepted for interface compatibility.
- class arm_loader.JSONArmLoader(model_package='arm_1_0')[source]
Bases:
DocumentLoaderLoads ARM-extended Define-XML JSON documents into the odmlib object model.
Handles ARM-specific elements such as AnalysisResultDisplays, ResultDisplay, AnalysisResult, ProgrammingCode, and AnalysisDatasets when loading from JSON format.
- Parameters:
model_package (str) – Package name (default: “arm_1_0”).
- load_document(odm_dict, key)[source]
Recursively load a dict into an odmlib object tree.
Instantiates the odmlib class named
keywith scalar attributes fromodm_dict, then recurses into nested dicts (ODMObject) and lists of dicts (ODMListObject).
- create_document_from_string(odm_string)[source]
Parse an ARM JSON string and store its contents internally.
- load_odm()[source]
Return the root ODM object loaded from the stored document.
Must be called after
create_document()orcreate_document_from_string().- Returns:
An odmlib
ODMroot object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet.
- Return type:
- load_metadataversion(idx=0)[source]
Return the MetaDataVersion from the stored document.
Handles both flat JSON (MetaDataVersion at root level) and nested formats (MetaDataVersion inside Study).
Must be called after
create_document()orcreate_document_from_string().- Parameters:
idx (int) – Unused; present for interface compatibility.
- Returns:
A
MetaDataVersionodmlib object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet, or if MetaDataVersion is not found in the document.
- Return type:
- load_study(idx=0)[source]
Return the Study from the stored document.
Must be called after
create_document()orcreate_document_from_string().- Parameters:
idx (int) – Unused; present for interface compatibility.
- Returns:
A
Studyodmlib object.- Raises:
OdmlibLoaderStateError – If no document has been loaded yet, or if Study is not found in the document.
- Return type:
odm_parser module
oid_generator module
Dynamic OID ref/def check generation from model introspection.
Inspects odmlib model class definitions to automatically derive:
Which classes are OID definitions (have an attribute named
OID).Which attributes are OID references (any attribute whose name contains
"OID"but is not the definition attribute itself).The mapping from reference attribute names to definition element classes.
The reverse mapping from definition element classes to reference attributes.
This replaces the manually-coded dictionaries in the rules/oid_ref.py
files for each model package. The dynamic system is derived directly from
the model classes, so it stays in sync automatically when the models evolve.
Usage:
from odmlib.oid_generator import create_oid_checker
checker = create_oid_checker("odm_1_3_2")
odm.verify_oids(checker)
Added in version 0.2.0.
- oid_generator.discover_model_classes(model_module)[source]
Return all ODMElement subclasses found in model_module.
- oid_generator.discover_oid_definitions(model_classes)[source]
Find all model classes that define an OID.
A class is a “definition” element when it has an attribute literally named
"OID"in its_attrsdict (regardless of descriptor type). This mirrors the runtime behaviour in_init_oid_check(), which registers anyattr == "OID"as a definition.
- oid_generator.discover_oid_references(model_classes)[source]
Find all OID reference attributes across all model classes.
An attribute is an OID reference when its name contains the substring
"OID"but is NOT itself named exactly"OID"(which would be a definition). This mirrors the runtime checkelif "OID" in attr: oid_checker.add_oid_ref(obj, attr)in_init_oid_check().
- oid_generator.build_ref_def_mapping(ref_attrs, oid_defs, model_classes)[source]
Build the mapping from reference attribute names to definition classes.
Resolution order for each reference attribute:
Check
_REF_DEF_OVERRIDES; only apply the override if its target class exists in model_classes (so the same override dict works for all model packages).Strip the
"OID"suffix from the attribute name and try<base>Deffirst, then<base>as the definition class name.
If neither step resolves to a known definition class, the attribute is not added to the mapping and will not be validated.
- Parameters:
ref_attrs (dict[str, list[str]]) – Mapping returned by
discover_oid_references().oid_defs (list[str]) – List returned by
discover_oid_definitions().model_classes (dict[str, type]) – Mapping returned by
discover_model_classes().
- Returns:
Mapping of
ref_attr_name → definition_class_name.- Return type:
- oid_generator.build_def_ref_mapping(ref_def)[source]
Build the reverse mapping from definition classes to reference attributes.
This is used by
DynamicOIDRef.check_unreferenced_oids()to find which reference attributes (if any) point to each definition class.
- class oid_generator.DynamicOIDRef(model_package, skip_attrs=None, skip_elems=None)[source]
Bases:
ErrorReportingDynamically-generated OID ref/def checker.
Drop-in replacement for the manually-coded
OIDRefclasses in therules/oid_ref.pyfiles. Introspects the model module at instantiation time to build the ref/def mappings automatically.Implements the same interface as the manual
OIDRefclasses so it can be passed directly toverify_oids().Via the
ErrorReportingmixin it also supports the collecting-checker protocol, sovalidate()withcollect_errors=Truereports every duplicate and every bad reference rather than only the first. The deprecated manualOIDRefclasses do not, and contribute at most one error.Note
A checker accumulates every OID it sees, so it is single-use per document. Call
reset()before validating a second document (or re-validating the same one), otherwise every OID is reported as a duplicate.- Parameters:
model_package (str) – Model package name, e.g.
"odm_1_3_2"or"define_2_1".skip_attrs (Optional[list[str]]) – Attribute names to ignore during validation (e.g.
["FileOID", "PriorFileOID"]).skip_elems (Optional[list[str]]) – Element class names to ignore when registering OID definitions (e.g.
["ODM"]).
Example:
from odmlib.oid_generator import create_oid_checker checker = create_oid_checker("odm_1_3_2") odm.verify_oids(checker)
Added in version 0.2.0.
- add_oid(oid, element)[source]
Register an OID definition.
Called automatically during
_init_oid_check()traversal.- Parameters:
- Raises:
OdmlibOIDError – If oid is already registered (duplicate OID). Inside a
collecting()block the error goes to the sink instead and the traversal continues, so the reference checks that follow still run.- Return type:
None
Note
On a duplicate, the first definition is kept — that is what the error message asserts, and it keeps
oidstable so the reference pass gives a deterministic verdict. A corner case worth knowing: if the first definition is askip_elemtype it lands only inunique_oids, so the reference pass then reports “not found” for everything pointing at it.
- add_oid_ref(oid, attr)[source]
Register an OID reference.
Called automatically during
_init_oid_check()traversal.
- is_oids_verified()[source]
Return
Trueifcheck_oid_refs()has been called.- Return type:
- check_oid_refs()[source]
Validate that all OID references point to valid definitions.
For each collected OID reference, checks:
The referenced OID exists in the OID definitions.
The definition element type matches what the reference attribute expects (per
ref_def).
- Returns:
Trueif all references are valid.- Raises:
OdmlibOIDError – On the first invalid or mismatched reference. Inside a
collecting()block every bad reference is reported to the sink instead.- Return type:
- reset()[source]
Clear all state collected by a previous verification pass.
A checker accumulates every OID it sees, so reusing one instance for a second document — or a second
validate()call on the same document — reports every OID as a duplicate. Callreset()between runs, or build a fresh checker withcreate_oid_checker().- Return type:
None
- oid_generator.create_oid_checker(model_package, extra_skip_attrs=None, extra_skip_elems=None)[source]
Create a
DynamicOIDRefchecker for a model package.This is the primary public API for creating OID checkers. It loads the per-model skip configuration from
odmlib.oid_generator_configand merges any caller-provided extras before constructing the checker.- Parameters:
model_package (str) – Model package name, e.g.
"odm_1_3_2","define_2_1","odm_2_0".extra_skip_attrs (list[str] | None) – Additional attribute names to skip during validation (merged with model-level defaults).
extra_skip_elems (list[str] | None) – Additional element class names to skip (merged with model-level defaults).
- Returns:
A configured
DynamicOIDRefinstance ready for use withverify_oids().- Return type:
Example:
from odmlib.oid_generator import create_oid_checker # Replace manual OIDRef usage: # from odmlib.odm_1_3_2.rules.oid_ref import OIDRef # checker = OIDRef() # With: checker = create_oid_checker("odm_1_3_2") odm.verify_oids(checker)
Added in version 0.2.0.
oid_generator_config module
Per-model skip configuration for dynamic OID ref/def generation.
Defines the skip_attr and skip_elem lists for each supported model
package. These lists mirror the hard-coded skip behaviour in the legacy
manual OIDRef classes:
skip_attr: OID-containing attribute names that should not be validated as OID references (e.g.
FileOID, which is a top-level file identifier, not a reference to another element).skip_elem: Element class names whose
OIDattributes should not be registered as definitions (e.g.ODM, whoseFileOIDis a file-level identifier rather than a metadata OID).
Usage (via odmlib.oid_generator.create_oid_checker()):
checker = create_oid_checker("define_2_1")
odm.verify_oids(checker)
Added in version 0.2.0.
oid_index module
schema_manager module
typed module
Type-validated descriptors for ODM element attributes.
This module defines descriptor classes that enforce type validation on ODM element attributes at assignment time. Each descriptor validates the type, format, or enumerated values of the assigned value.
- The descriptor hierarchy:
Typed– base type-checking descriptorPositive,NonNegative– numeric constraint mixinsPositiveInteger,NonNegativeInteger– combinedSized,SizedString– length-constrained stringsRegex,SizedRegexString– pattern-matchingDateTimeString,DateString,PartialDateTimeString,PartialDateString,PartialTimeString,IncompleteDateTimeString,IncompleteDateString,IncompleteTimeString,DurationDateTimeString– temporal typesValidValues,ExtendedValidValues– enumerated value validatorsValueSetString– combined enumerated + string validatorODMObject– single child ODM element containerODMListObject– list of child ODM elements container
- class typed.Typed(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorBase descriptor that validates value type on assignment.
Subclasses set
odm_typeto the expected Python type. RaisesOdmlibTypeErroron type mismatch.- Parameters:
- class typed.Integer(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for integer-valued ODM attributes.
Accepts int values and strings that convert to int (e.g., “42”). Used for OrderNumber, KeySequence, and similar integer attributes.
- class typed.Float(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for float-valued ODM attributes.
Accepts float, int, and string values that convert to float. Used for Rank attributes in CodeListItem and EnumeratedItem.
- class typed.String(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
TypedDescriptor for string-valued ODM attributes.
- Parameters:
- class typed.OID(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
TypedDescriptor for OID (Object Identifier) attributes.
OIDs uniquely identify definition elements within a MetaDataVersion. Used on the
OIDattribute of *Def elements (e.g.,ItemDef.OID).- Parameters:
- class typed.OIDRef(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
TypedDescriptor for OID reference attributes.
References the OID of a definition element. Used on reference elements (e.g.,
ItemRef.ItemOIDreferencesItemDef.OID).- Parameters:
- class typed.Name(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
TypedDescriptor for the Name attribute of ODM elements.
- Parameters:
- class typed.ID(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
TypedDescriptor for XML ID attributes.
- Parameters:
- class typed.IDRef(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
TypedDescriptor for XML IDREF attributes.
- Parameters:
- class typed.List(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
TypedDescriptor for list-valued attributes.
- Parameters:
- class typed.Dictionary(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
TypedDescriptor for dictionary-valued attributes.
- Parameters:
- class typed.Positive(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorMixin descriptor that enforces value > 0.
Raises
OdmlibTypeErrorif value is <= 0.
- class typed.NonNegative(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorMixin descriptor that enforces value >= 0.
Raises
OdmlibTypeErrorif value is < 0.
- class typed.PositiveInteger(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
-
Descriptor for positive integer attributes (value > 0).
Combines integer type validation with positive value constraint. Used for Length, ItemGroupDataSeq, and similar attributes.
- class typed.NonNegativeInteger(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
Integer,NonNegativeDescriptor for non-negative integer attributes (value >= 0).
Combines integer type validation with non-negative constraint. Used for SignificantDigits and similar attributes.
- class typed.PositiveFloat(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
-
Descriptor for positive float attributes (value > 0).
- class typed.NonNegativeFloat(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
Float,NonNegativeDescriptor for non-negative float attributes (value >= 0).
- class typed.Sized(*args, max_length, **kwargs)[source]
Bases:
DescriptorMixin descriptor that enforces a maximum string length.
- Parameters:
max_length (int) – Maximum allowed length of the string value.
- class typed.SizedString(*args, max_length, **kwargs)[source]
-
String descriptor with a maximum length constraint.
- class typed.Regex(*args, pat, **kwargs)[source]
Bases:
DescriptorDescriptor that validates a string against a regular expression pattern.
- Parameters:
pat (str) – Regular expression pattern the value must match.
- class typed.SizedRegexString(*args, max_length, **kwargs)[source]
Bases:
SizedString,RegexString descriptor with both size and regex constraints.
- class typed.DateTimeString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for ISO 8601 datetime strings.
Validates format:
YYYY-MM-DDTHH:MM:SS[.sss][Z|±HH:MM]Used for
CreationDateTime,AsOfDateTime, and similar attributes.
- class typed.PartialDateTimeString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for partial ISO 8601 datetime strings.
Allows partial date/time values where some components may be omitted.
- class typed.PartialDateString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for partial ISO 8601 date strings.
Accepts full
YYYY-MM-DD, year-monthYYYY-MM, or year-onlyYYYY.
- class typed.PartialTimeString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for partial ISO 8601 time strings.
Accepts full
HH:MM:SSor partial time values.
- class typed.IncompleteDateTimeString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for incomplete ISO 8601 datetime strings.
Allows
-as a placeholder for unknown date/time components.
- class typed.IncompleteDateString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for incomplete ISO 8601 date strings.
Allows
-as a placeholder for unknown date components.
- class typed.IncompleteTimeString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for incomplete ISO 8601 time strings.
Allows
-as a placeholder for unknown time components.
- class typed.DurationDateTimeString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for ISO 8601 duration strings.
Accepts the whole
durationDatetimeunion the ODM 2.0 XSD defines: the week form (P2W,-P1W), the general ISO 8601 form (P3D,P1Y2M,PT1H30M,P1DT2H3M4.5S), and the empty tag. Used for timing window attributes in ODM 2.0.Changed in version 0.2.1: Previously only
[+-]P{n}Wwas accepted, rejecting XSD-valid values such asP3DandPT1H.
- class typed.DateString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for ISO 8601 date strings (YYYY-MM-DD).
Used for
EffectiveDatein MetaDataVersionRef.
- class typed.SASName(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for SAS variable/dataset name attributes.
Validates that the value starts with a letter or underscore, contains only alphanumerics and underscores, and is at most 8 characters long. Used for SASFieldName, SASDatasetName, etc.
- class typed.SASFormat(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for SAS format name attributes.
Validates that the value starts with a letter, underscore, or
$, contains only alphanumerics, underscores, and dots, and is at most 8 characters long. Used for SASFormatName.
- class typed.Email(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for email address attributes.
Validates using the
validators.emailfunction.
- class typed.Url(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for URL attributes.
Validates using the
validators.urlfunction.
- class typed.FileName(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor for file name attributes.
Validates using
pathvalidate.is_valid_filename. Used for PdfFileName, PictureFileName, etc.
- class typed.ValidValues(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor that validates against a dynamically-loaded set of permitted values.
Looks up valid values from the ValueSet registry using the element class name and attribute name (e.g.,
ODM.FileType).
- class typed.ExtendedValidValues(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
DescriptorDescriptor that validates against an explicit list of permitted values.
Unlike ValidValues, the allowed values are provided at class definition time in the
valid_valueslist argument.
- class typed.ValueSetString(name=None, required=False, element_class=None, valid_values=None, namespace='odm')[source]
Bases:
ValidValues,StringString descriptor that validates against a dynamically-loaded set of permitted values.
Combines string type validation with value set membership checking. Used for attributes like FileType, Repeating, Mandatory, DataType, etc.
- class typed.ODMObject(*args, element_class, **kwargs)[source]
Bases:
DescriptorDescriptor for a single child ODM element.
Stores a reference to the element class and validates type on assignment. When accessed on an unset optional attribute, instantiates the element class with no arguments.
valueset module
- class valueset.ValueSetLoader[source]
Bases:
objectLoads and caches valueset data from JSON file
- classmethod get_version_for_module(module_path, instance_class=None)[source]
Determine the valueset version for a module path.
Resolution order: 1. Exact match in the version map. 2. Substring marker match against the module path. 3. If
instance_classis provided, walk its MRO and recurse on eachbase class’s module — this lets local models that subclass a shipped odmlib model inherit the correct version.
Fallback:
odm_1_3_2for backward compatibility.
- class valueset.ValueSet[source]
Bases:
objectBackward-compatible interface to valueset data.
Supports three entry types in valuesets.json: - list: A closed set of allowed string values (e.g.,
["Yes", "No"]) - regex dict: A dict with_regexkey and optional_description(e.g.,
{"_regex": "^2\\.[01](\\.\\d+)?$", "_description": "..."}).open dict: A dict with
_valuesand_open: truefor an extensible vocabulary — the XSD models these as a union of an enumeration with barexs:string, so any value is permitted while the listed terms remain the documented ones (e.g.,{"_values": ["Form", "Dataset"], "_open": true}).
Added in version 0.2.1: The open-dict form. ODM 2.0 uses extensible unions for
ItemGroupDef/@Type,TrialPhase/@ValueandStandard/@Status; enforcing them as closed lists rejected schema-valid documents.- UNKNOWN_ATTRIBUTE = <ValueSet.UNKNOWN_ATTRIBUTE>
Sentinel returned by
value_set()for an unknown attribute key (see_UnknownAttribute). Exposed for callers/tests.
- classmethod value_set(attribute, version=None, instance=None)[source]
Get the raw valueset entry for an attribute.
- Parameters:
attribute – “ClassName.AttributeName” format
version – Explicit version (e.g., “odm_2_0”) - optional
instance – ODMElement instance for automatic version detection - optional
- Returns:
A list of valid values, or a dict with
_regexkey for pattern-based validation. Returns theUNKNOWN_ATTRIBUTEsentinel if the attribute key is not registered for the resolved version or any fallback version.- Return type:
- Raises:
OdmlibValidationError – If the version is not found in the
valueset. An unknown attribute no longer raises — it returns –
:raises the
UNKNOWN_ATTRIBUTEsentinel instead.:
- classmethod validate(attribute, value, version=None, instance=None)[source]
Check whether a value is valid for the given attribute.
- Parameters:
attribute – “ClassName.AttributeName” format
value – The string value to validate
version – Explicit version (e.g., “odm_2_0”) - optional
instance – ODMElement instance for automatic version detection - optional
- Returns:
True if the value is valid, False otherwise.
- Return type:
- classmethod describe(attribute, version=None, instance=None)[source]
Return a human-readable description of valid values for an attribute.
- Parameters:
attribute – “ClassName.AttributeName” format
version – Explicit version (e.g., “odm_2_0”) - optional
instance – ODMElement instance for automatic version detection - optional
- Returns:
Description suitable for error messages.
- Return type:
mode module
Validation mode control for odmlib.
This module provides a context-managed permissive loading mode that allows
non-conformant ODM/Define-XML files to be loaded into the object model for
inspection and repair. The mode uses contextvars.ContextVar with a Flag
enum for graduated control over which validations to bypass.
Quick start:
from odmlib import permissive
with permissive():
loader.open_odm_document("broken.xml")
odm = loader.root()
# Mode is back to strict — fix issues, then validate
errors = odm.validate(collect_errors=True)
- class odmlib.mode.ValidationMode(*values)[source]
Bases:
FlagFlag enum controlling which validation categories are enforced.
Members can be combined with
|to create targeted relaxation:ValidationMode.SKIP_REQUIRED | ValidationMode.SKIP_VALUESET
- STRICT = 0
All validation enforced (default, preserves existing behavior).
- SKIP_REQUIRED = 1
Omit required-attribute checks during construction and access.
- SKIP_VALUESET = 2
Omit
ValidValuesandExtendedValidValuesenforcement.
- SKIP_TYPE = 4
Omit type checks and unknown-attribute rejection.
- SKIP_FORMAT = 8
Omit format validators (datetime, SAS name, email, URL, etc.).
- PERMISSIVE = 15
Composite flag that skips all validation categories.
- odmlib.mode.get_mode()[source]
Return the current validation mode from the ContextVar.
- Return type:
- odmlib.mode.set_mode(mode)[source]
Set the validation mode and return a reset token.
- Parameters:
mode (ValidationMode) – The validation mode to activate.
- Returns:
A
contextvars.Tokenthat can be passed to_validation_mode.reset()to restore the previous mode.- Return type:
- odmlib.mode.is_permissive(flag)[source]
Check whether a specific validation flag is active.
- Parameters:
flag (ValidationMode) – The validation category to check (e.g.,
ValidationMode.SKIP_REQUIRED).- Returns:
Trueif the flag is active in the current mode.- Return type:
- odmlib.mode.permissive(mode=<ValidationMode.PERMISSIVE: 15>)[source]
Context manager that activates a permissive validation mode.
On entry, sets the validation mode to mode. On exit (including on exception), restores the previous mode via token reset.
- Parameters:
mode (ValidationMode) – The validation mode to activate. Defaults to
ValidationMode.PERMISSIVE(skip all validation).
Example:
from odmlib import permissive, ValidationMode # Skip everything with permissive(): ... # Skip only required checks with permissive(ValidationMode.SKIP_REQUIRED): ...