Releases: swhume/odmlib
Release list
v0.2.0
[0.2.0]- 2026-06-23
Added
Context Manager write_on_exit Opt-Out
odmlib/context.py: addedwrite_on_exit: bool = Trueparameter to
ODMContext,DefineContext,open_odm, andopen_define. Passing
write_on_exit=Falsesuppresses the auto-save on clean exit, enabling
read-only inspection through the context managers without modifying or
creating any file. The default (True) preserves the documented
in-place save behaviour ? additive change, no compat impact.tests/test_context_managers.py: 10 new tests covering the opt-out
(XML, JSON,open_odm,open_define, and the input-preservation
regression guard for the default-output-file footgun) plus explicit
default-still-writes guards.
ODM v2.0 Model/XSD Alignment (safe subset)
odmlib/data/valuesets.json: added 12 missingodm_2_0value-set keys
(ReturnValue.DataType,ItemRef.Core/Repeat/Other/IsNonStandard/HasNoData,
CodeListItem.Other,Telecom.TelecomType,ItemGroupDef.IsNonStandard/HasNoData,
CodeList.IsNonStandard,ODM.Context) bound to the ODM 2.0
ODM-enumerations.xsdvalue lists.tests/test_odm_2_0_model.py: new construction + XML/JSON round-trip suite
for the major ODM 2.0 classes.tests/test_odm_2_0_known_gaps.py: new strict-xfailmarkers pinning the
five deferred structural ODM 2.0 model/XSD gaps so CI documents the known
state and fails loudly if a gap is silently fixed or regressed. (Its
ItemDef test is now a passing regression guard ? see Changed below.)
Changed
-
ODM 2.0
TranslatedText.Typeis now required (odmlib/odm_2_0/model.py),
matching the XSD (use="required", free-text media type).ODMBuilder
now defaultsType="text/plain"for the ODM 2.0 model shape only via a new
_translated_text()helper. -
odmlib/valueset.py:ValueSet.value_set()no longer raises for an
unknown attribute ? it returns the newValueSet.UNKNOWN_ATTRIBUTE
sentinel sovalidate()returnsFalseand theSKIP_VALUESETpermissive
guard can bypass an unregistered value set. Unknown version still raises.
Behavioral note: in strict mode an unregistered value-set attribute now
raisesOdmlibTypeError(fromValidValues.__set__) instead of the former
OdmlibValidationError(fromvalue_set()). -
ODM v2.0
ItemDefaligned with the ODM 2.0 XSD
(odmlib/odm_2_0/model.py). Removed the XSD-rejected attributes
FractionDigits,DatasetVarName, andSDSVarName; added the
XSD-defined optional attributesDisplayFormatandVariableSet. Code
that set the removed attributes on anodm_2_0ItemDefshould migrate ?
those values were schema-invalid and are no longer serialized. (Closes
the ROADMAP v0.2.1 ItemDef gap /ODM20-MODEL-XSD-DIFFERENCES_PLAN.md
�3.7; the XSDItemDef/ValueListRefchild element remains deferred.)
Known Limitations
- ODM v2.0 structural model/XSD gaps deferred to v0.2.1. Five features
produce schema-invalid output if used undermodel_package="odm_2_0":
ConditionDef(no requiredMethodSignature), text-based
FormalExpression,Protocol.StudyEventRef(removed in the 2.0 schema),
MetaDataVersion.StudyTimingplacement, andStudyEventGroupDef(missing
required child group). The affectedODMBuilderhelpers carry docstring
caveats. See ROADMAP "v0.2.1 ? ODM v2.0 Model/XSD Alignment" and
ODM20-MODEL-XSD-DIFFERENCES_PLAN.md.
ODM v2.0 XSD Schema Validation
odmlib/schema_manager.py: registered("odm", "2.0") ? "ODM.xsd"
in_MAIN_SCHEMA.ODMSchemaValidator(standard="odm", version="2.0")
now resolves the bundledodmlib/schemas/odm/2.0/ODM.xsd(target
namespacehttp://www.cdisc.org/ns/odm/v2.0) and exposes the same
validate_tree()/validate_file()API used for ODM 1.3.2 and
Define-XML.- The v2.0 XSD set (
ODM.xsd+ODM-foundation.xsd+ 7 modular
includes + xlink/xml/xhtml) was already shipping in
odmlib/schemas/odm/2.0/via theschemas/**/*.xsdpackage-data
glob; the registry entry is the only missing wiring. tests/test_schema_manager.py: 4 new tests verifying
get_schema_dir("odm", "2.0"),get_schema_path("odm", "2.0"),
the resolved filename (ODM.xsd), and the integration
file-existence check.tests/test_odm_validator.py: newTestODMv20Validatorclass
validatingtests/data/odmv2_example.xmland
tests/data/cdash_demo_v20.xmlend to end, plus a regression test
that an ODM 1.3.2 document fails v2.0 validation. New
test_explicit_odm_v20_works()in
TestODMValidatorConstructorContract.docs/source/guides/validation.rst: rewrote the "Schema Validation"
section to documentODMSchemaValidator(the previous text
referenced a nonexistentSchemaManagerclass).
Permissive Loading Mode
- New
odmlib/mode.pymodule withValidationModeflag enum and
permissive()context manager for loading non-conformant ODM documents ValidationMode.STRICT(default) ? all validation enforced (existing
behavior, unchanged)ValidationMode.SKIP_REQUIRED? omit required-attribute checks during
construction and accessValidationMode.SKIP_TYPE? omit type checks (Typed, Integer, Float,
ODMObject, ODMListObject, Positive, NonNegative, and unknown-attribute
rejection)ValidationMode.SKIP_FORMAT? omit format validators (datetime, SAS
name/format, email, URL, filename, regex, sized string)ValidationMode.SKIP_VALUESET? omit ValidValues and
ExtendedValidValues enforcementValidationMode.PERMISSIVE? composite flag that skips all validation
categoriespermissive()context manager with automatic cleanup via
contextvars.ContextVar; supports graduated control via flag
combinationsopen_odm()andopen_define()context managers accept
permissive=Trueor a specificValidationModecombinationValidationMode,permissive,get_mode,set_modeexported from
odmlibpackage root- New how-to guide:
docs/source/guides/permissive_loading.rst tests/test_permissive_mode.py? 70 tests covering all validation
categories, context manager safety, integration with loaders, and the
load-fix-validate workflow
Error Reporting and Diagnostics
- New
odmlib/exceptions.pymodule with a structured exception hierarchy OdmlibError? base class for all odmlib exceptionsOdmlibValidationError? replaces bareValueErrorfor validation failures; includes
element_path,hint,attribute,element_type, andactual_valueattributesOdmlibRequiredAttributeError? raised when a required attribute is missing at constructionOdmlibOIDError? raised for OID uniqueness or ref/def integrity failuresOdmlibConformanceError? raised when Cerberus conformance validation fails; exposes
rawcerberus_errorsdict for programmatic inspectionOdmlibElementOrderError? raised when child elements violate ODM-spec orderingOdmlibTypeError? replaces bareTypeErrorfor type/enum validation failuresOdmlibParsingError? raised when an XML or JSON document cannot be parsedOdmlibLoaderStateError? raised when a loader method is called before the document is openedOdmlibSerializationError? raised when the model cannot be serialized to XML or JSONOdmlibNamespaceError? raised for namespace registration or lookup failuresOdmlibWarning,OdmlibDeprecationWarning,OdmlibInteroperabilityWarning? warning hierarchyErrorCollector? accumulates validation errors instead of raising on the first failure;
has_errors,add_error(),add_warning(),raise_if_errors()APIODMElement.validate()method ? unified validation entry point supporting both
fail-fast (default) and collect-all-errors (collect_errors=True) modes- All exceptions and
ErrorCollectorexported fromodmlibpackage root tests/test_exceptions.py? 47 tests covering hierarchy, formatting, backward compat, and model integrationtests/test_collect_errors.py? 10 tests covering fail-fast and collect-all-errors validation modes
Dataset-JSON v1.1 ODMElement Model
- New
odmlib/dataset_json_1_1/package ? spec-conformant Dataset-JSON v1.1 support using
the ODMElement/descriptor pattern (one dataset per file, matching the v1.1 specification)DatasetJSON? root element withto_json(),from_json(),write_json(),read_json(),
write_ndjson(),read_ndjson(),to_dict(),from_dict(),add_row(),add_column(),
column_namespropertyColumn? column metadata with validateddataTypeand optionaltargetDataType,
length,displayFormat,keySequenceSourceSystem? optional nested source system metadata objectDatasetJSONElementbase class disables XML serialization (to_xml()raises
NotImplementedError) and handles mixed list types into_dict()
- New
odmlib/dataset_json_1_1/define_flattener.py? converts Define-XML v2.1 metadata into
11 tabular Dataset-JSON datasets (study, standards, datasets, variables, value_level,
where_clauses, methods, comments, documents, codelists, codelist_terms)DefineFlattener.flatten_all()returns dict of dataset name ? DatasetJSONDefineFlattener.write_all(output_dir)writes individual JSON files- O(1) ItemDef and WhereClauseDef lookups via index
_safe_get()utility for traversing deeply nested optional attributes
- New
odmlib/dataset_json_1_1/converter.py? bidirectional Dataset-XML ? Dataset-JSON v1.1dataset_xml_to_dataset_json(odm_obj)returns dict[str, DatasetJSON] (one per ItemGroupOID)dataset_json_to_dataset_xml(dataset_json, model)converts back to Dataset-XML
- Updated
odmlib/dataframe.py? Pandas integration for the new modeldataset_json_to_dataframe()? DatasetJSON v1.1 ? DataFrame- `define...
v0.2.0rc1
[0.2.0] - 2026-05-20
An rc1 - testing release note. Install for soak with: pip install --pre "odmlib==0.2.0rc1".
Added
Context Manager write_on_exit Opt-Out
odmlib/context.py: addedwrite_on_exit: bool = Trueparameter to
ODMContext,DefineContext,open_odm, andopen_define. Passing
write_on_exit=Falsesuppresses the auto-save on clean exit, enabling
read-only inspection through the context managers without modifying or
creating any file. The default (True) preserves the documented
in-place save behaviour ? additive change, no compat impact.tests/test_context_managers.py: 10 new tests covering the opt-out
(XML, JSON,open_odm,open_define, and the input-preservation
regression guard for the default-output-file footgun) plus explicit
default-still-writes guards.
ODM v2.0 Model/XSD Alignment (safe subset)
odmlib/data/valuesets.json: added 12 missingodm_2_0value-set keys
(ReturnValue.DataType,ItemRef.Core/Repeat/Other/IsNonStandard/HasNoData,
CodeListItem.Other,Telecom.TelecomType,ItemGroupDef.IsNonStandard/HasNoData,
CodeList.IsNonStandard,ODM.Context) bound to the ODM 2.0
ODM-enumerations.xsdvalue lists.tests/test_odm_2_0_model.py: new construction + XML/JSON round-trip suite
for the major ODM 2.0 classes.tests/test_odm_2_0_known_gaps.py: new strict-xfailmarkers pinning the
five deferred structural ODM 2.0 model/XSD gaps so CI documents the known
state and fails loudly if a gap is silently fixed or regressed. (Its
ItemDef test is now a passing regression guard ? see Changed below.)
Changed
-
ODM 2.0
TranslatedText.Typeis now required (odmlib/odm_2_0/model.py),
matching the XSD (use="required", free-text media type).ODMBuilder
now defaultsType="text/plain"for the ODM 2.0 model shape only via a new
_translated_text()helper. -
odmlib/valueset.py:ValueSet.value_set()no longer raises for an
unknown attribute ? it returns the newValueSet.UNKNOWN_ATTRIBUTE
sentinel sovalidate()returnsFalseand theSKIP_VALUESETpermissive
guard can bypass an unregistered value set. Unknown version still raises.
Behavioral note: in strict mode an unregistered value-set attribute now
raisesOdmlibTypeError(fromValidValues.__set__) instead of the former
OdmlibValidationError(fromvalue_set()). -
ODM v2.0
ItemDefaligned with the ODM 2.0 XSD
(odmlib/odm_2_0/model.py). Removed the XSD-rejected attributes
FractionDigits,DatasetVarName, andSDSVarName; added the
XSD-defined optional attributesDisplayFormatandVariableSet. Code
that set the removed attributes on anodm_2_0ItemDefshould migrate ?
those values were schema-invalid and are no longer serialized. (Closes
the ROADMAP v0.2.1 ItemDef gap /ODM20-MODEL-XSD-DIFFERENCES_PLAN.md
�3.7; the XSDItemDef/ValueListRefchild element remains deferred.)
Known Limitations
- ODM v2.0 structural model/XSD gaps deferred to v0.2.1. Five features
produce schema-invalid output if used undermodel_package="odm_2_0":
ConditionDef(no requiredMethodSignature), text-based
FormalExpression,Protocol.StudyEventRef(removed in the 2.0 schema),
MetaDataVersion.StudyTimingplacement, andStudyEventGroupDef(missing
required child group). The affectedODMBuilderhelpers carry docstring
caveats. See ROADMAP "v0.2.1 ? ODM v2.0 Model/XSD Alignment" and
ODM20-MODEL-XSD-DIFFERENCES_PLAN.md.
ODM v2.0 XSD Schema Validation
odmlib/schema_manager.py: registered("odm", "2.0") ? "ODM.xsd"
in_MAIN_SCHEMA.ODMSchemaValidator(standard="odm", version="2.0")
now resolves the bundledodmlib/schemas/odm/2.0/ODM.xsd(target
namespacehttp://www.cdisc.org/ns/odm/v2.0) and exposes the same
validate_tree()/validate_file()API used for ODM 1.3.2 and
Define-XML.- The v2.0 XSD set (
ODM.xsd+ODM-foundation.xsd+ 7 modular
includes + xlink/xml/xhtml) was already shipping in
odmlib/schemas/odm/2.0/via theschemas/**/*.xsdpackage-data
glob; the registry entry is the only missing wiring. tests/test_schema_manager.py: 4 new tests verifying
get_schema_dir("odm", "2.0"),get_schema_path("odm", "2.0"),
the resolved filename (ODM.xsd), and the integration
file-existence check.tests/test_odm_validator.py: newTestODMv20Validatorclass
validatingtests/data/odmv2_example.xmland
tests/data/cdash_demo_v20.xmlend to end, plus a regression test
that an ODM 1.3.2 document fails v2.0 validation. New
test_explicit_odm_v20_works()in
TestODMValidatorConstructorContract.docs/source/guides/validation.rst: rewrote the "Schema Validation"
section to documentODMSchemaValidator(the previous text
referenced a nonexistentSchemaManagerclass).
Permissive Loading Mode
- New
odmlib/mode.pymodule withValidationModeflag enum and
permissive()context manager for loading non-conformant ODM documents ValidationMode.STRICT(default) ? all validation enforced (existing
behavior, unchanged)ValidationMode.SKIP_REQUIRED? omit required-attribute checks during
construction and accessValidationMode.SKIP_TYPE? omit type checks (Typed, Integer, Float,
ODMObject, ODMListObject, Positive, NonNegative, and unknown-attribute
rejection)ValidationMode.SKIP_FORMAT? omit format validators (datetime, SAS
name/format, email, URL, filename, regex, sized string)ValidationMode.SKIP_VALUESET? omit ValidValues and
ExtendedValidValues enforcementValidationMode.PERMISSIVE? composite flag that skips all validation
categoriespermissive()context manager with automatic cleanup via
contextvars.ContextVar; supports graduated control via flag
combinationsopen_odm()andopen_define()context managers accept
permissive=Trueor a specificValidationModecombinationValidationMode,permissive,get_mode,set_modeexported from
odmlibpackage root- New how-to guide:
docs/source/guides/permissive_loading.rst tests/test_permissive_mode.py? 70 tests covering all validation
categories, context manager safety, integration with loaders, and the
load-fix-validate workflow
Error Reporting and Diagnostics
- New
odmlib/exceptions.pymodule with a structured exception hierarchy OdmlibError? base class for all odmlib exceptionsOdmlibValidationError? replaces bareValueErrorfor validation failures; includes
element_path,hint,attribute,element_type, andactual_valueattributesOdmlibRequiredAttributeError? raised when a required attribute is missing at constructionOdmlibOIDError? raised for OID uniqueness or ref/def integrity failuresOdmlibConformanceError? raised when Cerberus conformance validation fails; exposes
rawcerberus_errorsdict for programmatic inspectionOdmlibElementOrderError? raised when child elements violate ODM-spec orderingOdmlibTypeError? replaces bareTypeErrorfor type/enum validation failuresOdmlibParsingError? raised when an XML or JSON document cannot be parsedOdmlibLoaderStateError? raised when a loader method is called before the document is openedOdmlibSerializationError? raised when the model cannot be serialized to XML or JSONOdmlibNamespaceError? raised for namespace registration or lookup failuresOdmlibWarning,OdmlibDeprecationWarning,OdmlibInteroperabilityWarning? warning hierarchyErrorCollector? accumulates validation errors instead of raising on the first failure;
has_errors,add_error(),add_warning(),raise_if_errors()APIODMElement.validate()method ? unified validation entry point supporting both
fail-fast (default) and collect-all-errors (collect_errors=True) modes- All exceptions and
ErrorCollectorexported fromodmlibpackage root tests/test_exceptions.py? 47 tests covering hierarchy, formatting, backward compat, and model integrationtests/test_collect_errors.py? 10 tests covering fail-fast and collect-all-errors validation modes
Dataset-JSON v1.1 ODMElement Model
- New
odmlib/dataset_json_1_1/package ? spec-conformant Dataset-JSON v1.1 support using
the ODMElement/descriptor pattern (one dataset per file, matching the v1.1 specification)DatasetJSON? root element withto_json(),from_json(),write_json(),read_json(),
write_ndjson(),read_ndjson(),to_dict(),from_dict(),add_row(),add_column(),
column_namespropertyColumn? column metadata with validateddataTypeand optionaltargetDataType,
length,displayFormat,keySequenceSourceSystem? optional nested source system metadata objectDatasetJSONElementbase class disables XML serialization (to_xml()raises
NotImplementedError) and handles mixed list types into_dict()
- New
odmlib/dataset_json_1_1/define_flattener.py? converts Define-XML v2.1 metadata into
11 tabular Dataset-JSON datasets (study, standards, datasets, variables, value_level,
where_clauses, methods, comments, documents, codelists, codelist_terms)DefineFlattener.flatten_all()returns dict of dataset name ? DatasetJSONDefineFlattener.write_all(output_dir)writes individual JSON files- O(1) ItemDef and WhereClauseDef lookups via index
_safe_get()utility for traversing deeply nested optional attributes
- New
odmlib/dataset_json_1_1/converter.py? bidirectional Dataset-XML ? Dataset-JSON v1.1dataset_xml_to_dataset_json(odm_obj)returns dict[str, DatasetJSON] (one per ItemGroupOID)dataset_json_to_dataset_xml(dataset_json, model)converts back to Dataset-XML
- Updated
odmlib/dataframe.py? Pandas integratio...
Release v0.1.4
Release v0.1.4: This code has been available for a bit, but v0.2.0, with many improvements, is coming soon. So, I'm tagging this release for those who may need to access it. Version 0.1.4 is also available via PyPI.