Skip to content
Accessibility palettes

API reference

Generated from the docstrings in the source.

This page covers the public API: what import ddi_l exposes and what semantic versioning applies to. For the wider model layer, see Models reference for the guided tour and Schema coverage for what is supported at which level.

Where to start

new_study() and open_ddi() return a Document, which is the front door. DDIDocument, DDIFragment and StudyCursor are the advanced layer underneath it. Reach for them when you need to work with raw elements, partial instances, or a specific study in a multi-study file.

Creating and opening documents

Create a new DDI document with a StudyUnit.

Parameters:

Name Type Description Default
title str

Human-readable title for the study.

required
agency str

Maintenance agency responsible for the study.

required
identifier str | None

Optional identifier; auto-generated if omitted.

None
version str

Version string for the study.

'1'
lang str

Language tag for the study's title and abstract, and for the labels put on the module and scheme wrappers the helpers generate.

'en'

Returns:

Name Type Description
Document Document

A new document ready for adding content.

Example

import ddi_l as ddi doc = ddi.new_study(title="My Survey", agency="example.org")

Open a DDI XML file.

Parameters:

Name Type Description Default
path str | Path

Filesystem path to read.

required
validate bool

Whether to validate against the DDI schema on load.

False

Returns:

Name Type Description
Document Document

The parsed document.

Example

import ddi_l as ddi doc = ddi.open_ddi("study.xml")

Document

Document

Document(inner: DDIDocument)

A DDI Lifecycle 3.3 document with a simple CRUD API.

This is the primary interface for creating, reading, updating, and deleting content in DDI documents. It manages a single StudyUnit and provides convenience methods for common operations.

Parameters:

Name Type Description Default
inner DDIDocument

The underlying DDIDocument instance.

required
Example

import ddi_l as ddi doc = ddi.new_study(title="My Survey", agency="example.org") q = doc.add_question(text="How old are you?") doc.save("my-study.xml")

agency property

agency: str

str: The agency of the primary StudyUnit.

title property

title: str | None

Return the study's citation title, or None when unavailable.

Reads the citation title from the StudyUnit when it carries its own r:Citation, then the document-level one written by :func:new_study (and preserved by :func:open_ddi), falling back last to the StudyUnit's first abstract.

groups property

groups

list[Group]: groups declared directly under the DDIInstance.

ddi_profiles property

ddi_profiles

list[DDIProfile]: DDIProfiles declared on the DDIInstance.

comparisons property

comparisons

list[Comparison]: comparisons declared in the document's group.

archives property

archives: list[Archive]

list[Archive]: Archive modules on the primary study.

resource_packages property

resource_packages: list[ResourcePackage]

list[ResourcePackage]: ResourcePackages on the DDIInstance.

local_holding_packages property

local_holding_packages: list[LocalHoldingPackage]

list[LocalHoldingPackage]: LocalHoldingPackages on the DDIInstance.

translation_information property

translation_information: TranslationInformation | None

TranslationInformation | None: the instance's translation info.

questions property

questions: list[QuestionItem]

list[QuestionItem]: All questions in the document.

variables property

variables: list[Variable]

list[Variable]: All variables in the document.

concepts property

concepts: list[Concept]

list[Concept]: All concepts in the document.

universes property

universes: list[Universe]

list[Universe]: All universes in the document.

code_lists property

code_lists: list[CodeList]

list[CodeList]: All code lists in the document.

study_unit property

study_unit: StudyUnit

StudyUnit: The document's active :class:StudyUnit model object.

Use this to reach study-level metadata the CRUD helpers do not cover --- versioning (:meth:~MaintainableBase.increment_minor_version), version rationales, custom properties on the study itself.

The object is live: mutating it changes the document, and the changes are serialized by :meth:save, :meth:to_xml and :meth:validate.

Raises:

Type Description
DDIModelError

If the document contains no StudyUnit.

Example

import ddi_l as ddi doc = ddi.new_study(title="My Survey", agency="example.org") doc.study_unit.increment_minor_version()

inner property

inner: DDIDocument

DDIDocument: The underlying XML-level document, for advanced use.

Accessing it hands the XML tree to the caller: pending edits are written out and model objects obtained earlier from this :class:Document are detached, so later XML edits are picked up.

add_question

add_question(
    text: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
) -> QuestionItem

Add a question to the document.

Parameters:

Name Type Description Default
text str

The question text.

required
lang str

Language tag for the text.

'en'
label str | None

Optional human-readable label. Supplying one keeps the document clean under the ddi.maintainable.labels lint rule.

None
label_lang str | None

Language tag for label; defaults to lang.

None
identifier str | None

Optional identifier; auto-generated if omitted.

None

Returns:

Name Type Description
QuestionItem QuestionItem

The newly created question.

add_variable

add_variable(
    name: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    question: QuestionItem | Reference | None = None,
    concept: Concept | Reference | None = None,
    identifier: str | None = None,
) -> Variable

Add a variable to the document.

Parameters:

Name Type Description Default
name str

The variable name.

required
lang str

Language tag for the name.

'en'
label str | None

Optional human-readable label. Supplying one keeps the document clean under the ddi.maintainable.labels lint rule.

None
label_lang str | None

Language tag for label; defaults to lang.

None
question QuestionItem | Reference | None

Optional question to link via reference.

None
concept Concept | Reference | None

Optional concept to link via reference.

None
identifier str | None

Optional identifier; auto-generated if omitted.

None

Returns:

Name Type Description
Variable Variable

The newly created variable.

add_concept

add_concept(
    name: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
) -> Concept

Add a concept to the document.

Parameters:

Name Type Description Default
name str

The concept name.

required
lang str

Language tag for the name.

'en'
label str | None

Optional human-readable label. Supplying one keeps the document clean under the ddi.maintainable.labels lint rule.

None
label_lang str | None

Language tag for label; defaults to lang.

None
identifier str | None

Optional identifier; auto-generated if omitted.

None

Returns:

Name Type Description
Concept Concept

The newly created concept.

add_universe

add_universe(
    name: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
) -> Universe

Add a universe to the document.

Parameters:

Name Type Description Default
name str

The universe name.

required
lang str

Language tag for the name.

'en'
label str | None

Optional human-readable label. Supplying one keeps the document clean under the ddi.maintainable.labels lint rule.

None
label_lang str | None

Language tag for label; defaults to lang.

None
identifier str | None

Optional identifier; auto-generated if omitted.

None

Returns:

Name Type Description
Universe Universe

The newly created universe.

add_code_list

add_code_list(
    name: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
) -> CodeList

Add a code list to the document.

Parameters:

Name Type Description Default
name str

The code list name.

required
lang str

Language tag for the name.

'en'
label str | None

Optional human-readable label. Supplying one keeps the document clean under the ddi.maintainable.labels lint rule.

None
label_lang str | None

Language tag for label; defaults to lang.

None
identifier str | None

Optional identifier; auto-generated if omitted.

None

Returns:

Name Type Description
CodeList CodeList

The newly created code list.

add_item

add_item(
    item_type: type[MaintainableBase],
    *,
    name: str | None = None,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
    **kwargs: object,
) -> MaintainableBase

Add an item of any registered type to the document.

Parameters:

Name Type Description Default
item_type type[MaintainableBase]

The MaintainableBase subclass to create (e.g. Category, Instrument, RepresentedVariable).

required
name str | None

Display name for the item. Passed as names for most types, or as question_texts for QuestionItem.

None
lang str

Language tag for name.

'en'
label str | None

Optional human-readable label. Supplying one keeps the document clean under the ddi.maintainable.labels lint rule. Ignored for types the DDI schema gives no r:Label slot.

None
label_lang str | None

Language tag for label; defaults to lang.

None
identifier str | None

Optional identifier; auto-generated if omitted.

None
**kwargs object

Extra keyword arguments forwarded to the item constructor.

{}

Returns:

Type Description
MaintainableBase

An instance of item_type that has been added to the document.

Raises:

Type Description
TypeError

If item_type is not in the item registry.

add_record_layout

add_record_layout(
    *,
    identifier: str | None = None,
    logical_record: LogicalRecord | None = None,
) -> RecordLayout

Create a record layout that maps variables to positions in a file.

Builds a backing physical structure and a linked RecordLayout, both stored on the study and serialized inside a PhysicalDataProduct. Add variable-to-position mappings on the returned layout with :meth:RecordLayout.add_data_item::

rl = doc.add_record_layout()
rl.add_data_item(age.to_reference(), start_position=1, width=2)

Pass logical_record (from :meth:DataRelationship.add_logical_record) to tie the backing physical structure to that logical record, so the layout describes a modeled record rather than a placeholder.

Returns:

Name Type Description
RecordLayout RecordLayout

the new, document-attached record layout.

add_dataset

add_dataset(
    *,
    name: str | None = None,
    identifier: str | None = None,
    lang: str = "en",
) -> DataSet

Create an inline dataset (data values stored in the document).

Add values on the returned dataset with :meth:DataSet.add_item_value::

ds = doc.add_dataset(name="Sample rows")
ds.add_item_value(age.to_reference(), record="1", value="42")

Returns:

Name Type Description
DataSet DataSet

the new, document-attached inline dataset.

add_data_relationship

add_data_relationship(
    *,
    identifier: str | None = None,
    label: str | None = None,
    lang: str = "en",
) -> DataRelationship

Create a data relationship in the logical product.

A data relationship groups the dataset's logical records. Add records with :meth:DataRelationship.add_logical_record::

dr = doc.add_data_relationship()
dr.add_logical_record()  # all variables in one rectangular record

Returns:

Name Type Description
DataRelationship DataRelationship

the new, document-attached data relationship.

add_ncube

add_ncube(
    *,
    name: str | None = None,
    identifier: str | None = None,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
) -> NCube

Create a multidimensional cube (NCube) in the logical product.

Add axes and measured values on the returned cube::

cube = doc.add_ncube(name="Population by year and region")
cube.add_dimension(year.to_reference())
cube.add_dimension(region.to_reference())
cube.add_measure(population.to_reference())

Returns:

Name Type Description
NCube NCube

the new, document-attached cube.

add_group

add_group(*, identifier: str | None = None)

Organize the document's study into a Group (study series/package).

The StudyUnit is moved under a new <g:Group> in the DDIInstance. The document stays fully editable: add_variable, add_question, and the rest still resolve to the now-grouped study. Returns the new Group.

add_ddi_profile

add_ddi_profile(
    *,
    name: str | None = None,
    x_path_version: float = 1.0,
    used_xpaths: Iterable[str] | None = None,
    identifier: str | None = None,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
) -> DDIProfile

Attach a DDIProfile declaring which DDI elements are used.

Pass used_xpaths for the common case, or call :meth:DDIProfile.add_used on the returned profile; it is re-serialized on save either way::

profile = doc.add_ddi_profile(name="Deposit profile")
profile.add_used("//s:StudyUnit", is_required=True)

Returns:

Name Type Description
DDIProfile DDIProfile

the new profile, attached at the DDIInstance level.

add_study

add_study(
    *,
    title: str,
    identifier: str | None = None,
    lang: str | None = None,
) -> StudyUnit

Add an additional StudyUnit to the document's group (a study series).

The document is organized into a group if it is not already. The new study is returned for model-layer building; it is re-serialized into the group on save. To target it with the high-level add_* helpers, use the cursor from :meth:study::

wave2 = doc.add_study(title="Wave 2")
doc.study(wave2.identifier).add_variable(name="income")

Parameters:

Name Type Description Default
title str

Title of the new study.

required
identifier str | None

Optional identifier; generated when omitted.

None
lang str | None

Language of title; defaults to the document's language.

None

Returns:

Name Type Description
StudyUnit StudyUnit

the new, group-attached study unit.

study

study(identifier: str | None = None) -> StudyCursor

Return a cursor whose add_* helpers target a specific study.

With no identifier (or the primary study's id) the cursor targets the primary study; otherwise it targets a study previously added with :meth:add_study. This is how you edit a non-primary study in a multi-study series::

doc.study(wave2.identifier).add_variable(name="income")

Returns:

Name Type Description
StudyCursor StudyCursor

a cursor bound to the resolved study.

Raises:

Type Description
DDIReferenceError

If no study matches identifier (a :class:LookupError).

add_comparison

add_comparison(
    *,
    name: str | None = None,
    identifier: str | None = None,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
) -> Comparison

Add a Comparison (harmonization maps) to the document's group.

Map items across studies/versions on the returned comparison::

cmp = doc.add_comparison(name="2020 to 2021")
cmp.add_variable_map(age_2020.to_reference(), age_2021.to_reference())

Returns:

Name Type Description
Comparison Comparison

the new, group-attached comparison.

add_archive

add_archive(
    *,
    identifier: str | None = None,
    label: str | None = None,
    lang: str = "en",
) -> Archive

Attach an Archive module to the primary study.

The archive holds archive-specific lifecycle metadata for the study. Populate it further on the returned model object; it is re-serialized on save.

Returns:

Name Type Description
Archive Archive

the new archive, attached to the primary StudyUnit.

add_resource_package

add_resource_package(
    *, identifier: str | None = None
) -> ResourcePackage

Attach a ResourcePackage (reusable metadata) to the DDIInstance.

Returns:

Name Type Description
ResourcePackage ResourcePackage

the new package, at the DDIInstance level.

add_local_holding_package

add_local_holding_package(
    *,
    depository_study_unit: MaintainableBase
    | Reference
    | None = None,
    identifier: str | None = None,
) -> LocalHoldingPackage

Attach a LocalHoldingPackage recording a local holding.

A local holding package references the deposited object it holds. By default it points at the primary study; pass depository_study_unit to reference a different study unit.

Returns:

Name Type Description
LocalHoldingPackage LocalHoldingPackage

the new package, at the DDIInstance level.

add_translation_information

add_translation_information(
    *,
    languages: Iterable[str] | None = None,
    description: str | None = None,
    lang: str = "en",
) -> TranslationInformation

Set the DDIInstance TranslationInformation.

Describes which languages are involved in translating the instance, with an optional description. Replaces any existing translation information.

Returns:

Name Type Description
TranslationInformation TranslationInformation

the translation information element.

items

items(
    item_type: type[MaintainableBase],
) -> list[MaintainableBase]

Return all items of item_type in the document.

Parameters:

Name Type Description Default
item_type type[MaintainableBase]

The MaintainableBase subclass to query (e.g. Category, Instrument, RepresentedVariable).

required

Returns:

Name Type Description
list list[MaintainableBase]

All items of the requested type.

Raises:

Type Description
TypeError

If item_type is not in the item registry.

find

find(identifier: str | None) -> Any | None

Find an item by identifier in any study of the document.

Parameters:

Name Type Description Default
identifier str | None

The identifier to search for.

required

Returns:

Type Description
Any | None

The matching model object, or None (always None when

Any | None

identifier is None).

remove

remove(identifier: str | None) -> bool

Remove an item by identifier from any study of the document.

References to the removed item elsewhere in the document are left in place; :meth:validate reports them as dangling.

Parameters:

Name Type Description Default
identifier str | None

The identifier of the item to remove.

required

Returns:

Name Type Description
bool bool

True if an item was removed, False if not found.

save

save(
    path: str | Path, *, pretty_print: bool = True
) -> None

Save the document to an XML file.

Parameters:

Name Type Description Default
path str | Path

Filesystem path to write to.

required
pretty_print bool

Format the output for readability.

True

Warns:

Type Description
DDIReferenceWarning

If a reference in the study points at an item the document does not contain.

to_xml

to_xml(*, pretty_print: bool = True) -> str

Serialize the document to an XML string.

Parameters:

Name Type Description Default
pretty_print bool

Format the output for readability.

True

Returns:

Name Type Description
str str

UTF-8 XML representation, including the XML declaration.

validate

validate() -> list

Validate the document against the DDI schema.

Returns:

Name Type Description
list list

Schema validation issues; empty if valid.

lint

lint(
    rules: Sequence[str] | None = None,
) -> list[LintFinding]

Run the lint rules against the document.

Parameters:

Name Type Description Default
rules Sequence[str] | None

Rule identifiers to run; None runs the default set.

None

Returns:

Type Description
list[LintFinding]

list[LintFinding]: Findings; empty when the document is clean.

StudyCursor

StudyCursor

StudyCursor(document: Document, study: StudyUnit)

A handle to one study whose add_* helpers target that study.

Obtained from :meth:Document.study. Each method forwards to the matching :class:Document helper with this cursor's study as the target, so the same validation and serialization apply. This is how you edit a non-primary study in a multi-study series.

study_unit property

study_unit: StudyUnit

StudyUnit: the study this cursor targets.

identifier property

identifier: str | None

Return the identifier of the targeted study (or None).

add_question

add_question(
    text: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
) -> QuestionItem

Add a question to this study (see :meth:Document.add_question).

add_variable

add_variable(
    name: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    question: QuestionItem | Reference | None = None,
    concept: Concept | Reference | None = None,
    identifier: str | None = None,
) -> Variable

Add a variable to this study (see :meth:Document.add_variable).

add_concept

add_concept(
    name: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
) -> Concept

Add a concept to this study (see :meth:Document.add_concept).

add_universe

add_universe(
    name: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
) -> Universe

Add a universe to this study (see :meth:Document.add_universe).

add_code_list

add_code_list(
    name: str,
    *,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
) -> CodeList

Add a code list to this study (see :meth:Document.add_code_list).

add_item

add_item(
    item_type: type[MaintainableBase],
    *,
    name: str | None = None,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
    identifier: str | None = None,
    **kwargs: object,
) -> MaintainableBase

Add any registered item to this study (see :meth:Document.add_item).

add_ncube

add_ncube(
    *,
    name: str | None = None,
    identifier: str | None = None,
    lang: str = "en",
    label: str | None = None,
    label_lang: str | None = None,
) -> NCube

Add an NCube to this study (see :meth:Document.add_ncube).

add_data_relationship

add_data_relationship(
    *,
    identifier: str | None = None,
    label: str | None = None,
    lang: str = "en",
) -> DataRelationship

Add a data relationship (see :meth:Document.add_data_relationship).

add_record_layout

add_record_layout(
    *,
    identifier: str | None = None,
    logical_record: LogicalRecord | None = None,
) -> RecordLayout

Add a record layout (see :meth:Document.add_record_layout).

add_dataset

add_dataset(
    *,
    name: str | None = None,
    identifier: str | None = None,
    lang: str = "en",
) -> DataSet

Add an inline dataset (see :meth:Document.add_dataset).

add_archive

add_archive(
    *,
    identifier: str | None = None,
    label: str | None = None,
    lang: str = "en",
) -> Archive

Add an archive to this study (see :meth:Document.add_archive).

Reading and writing

Parse source into a :class:DDIDocument or :class:DDIFragment.

Parameters:

Name Type Description Default
source SourceType

The DDI instance XML to parse. Accepts filesystem paths, strings, bytes, or file-like objects.

required
validate bool

Whether to validate the parsed document against the DDI XML schema.

False
build_index bool

Build the resolver index now. By default it is built on first use of :attr:DDIDocument.resolver.

False
version str | None

Optional DDI schema version override used when validating the parsed document.

None

Returns:

Name Type Description
A DDIWrapper

class:DDIDocument when the root element is DDIInstance or a

DDIWrapper

class:DDIFragment when the root element is FragmentInstance.

Raises:

Type Description
FileNotFoundError

Propagated when source is a :class:~pathlib.Path that does not exist.

TypeError

Raised when source is not a supported input type.

ValueError

Raised when the parsed XML root is not a valid DDI instance or fragment tag.

DDIReadError

Raised when XML parsing fails because the input is malformed or cannot be read.

Serialize a document to destination (or return bytes when omitted).

Parameters:

Name Type Description Default
document_or_element DocumentLike

A DDI document wrapper, maintainable object, element, or serialized XML that should be emitted as XML.

required
destination str | Path | BinaryIO | TextIO | None

Optional output location. When None, bytes are returned. When a path-like object, bytes are written to disk. When a writable binary or text stream, the serialized XML is written to the stream.

None
pretty_print bool

Whether to format the XML output with indentation when supported by the underlying XML backend.

True
xml_declaration bool

Whether to include the XML declaration at the start of the serialized output.

True
encoding str

Text encoding used when writing XML bytes or decoding to text streams.

'utf-8'
version str | None

Optional DDI schema version override used to assert the target release is supported when specified.

None

Returns:

Type Description
bytes

The serialized XML bytes regardless of destination.

Raises:

Type Description
DDIWriteError

Raised when serialization or writing to the destination fails.

Stream maintainable objects from a DDI instance document.

Every element whose tag matches a requested type is yielded, fully populated, when its end tag is reached. Maintainables nested inside another requested maintainable are yielded as well and kept in the tree until the enclosing one is built. Once an element is no longer inside a requested match it is cleared, so memory is bounded by the largest outermost match. Request only the types you need, as :func:iter_variables does, to keep that bound small.

Parameters:

Name Type Description Default
source SourceType

The XML content to parse, provided as a path, serialized XML, or file-like object.

required
maintainable_types Sequence[type[MaintainableBase]] | None

Classes to instantiate when their XML tags are encountered. Defaults to every registered maintainable type.

None
**kwargs object

Additional keyword arguments forwarded to :func:etree.iterparse.

{}

Yields:

Type Description
MaintainableBase

Instances of the requested maintainable classes, innermost first.

Iterate over :class:Variable maintainables in a DDI instance.

Parameters:

Name Type Description Default
source SourceType

The XML content to parse for Variable maintainables.

required
**kwargs object

Additional keyword arguments forwarded to :func:iterparse_ddi.

{}

Returns:

Type Description
Iterator[Variable]

An iterator yielding :class:Variable objects as they are parsed from

Iterator[Variable]

source.

Side Effects

Consumes the input stream and prunes processed XML elements via :func:iterparse_ddi to minimize memory usage.

Iterate over :class:QuestionItem maintainables in a DDI instance.

Parameters:

Name Type Description Default
source SourceType

The XML content to parse for QuestionItem maintainables.

required
**kwargs object

Additional keyword arguments forwarded to :func:iterparse_ddi.

{}

Returns:

Type Description
Iterator[QuestionItem]

An iterator yielding :class:QuestionItem objects as they are parsed

Iterator[QuestionItem]

from source.

Side Effects

Consumes the input stream and prunes processed XML elements via :func:iterparse_ddi to minimize memory usage.

Validation

Validate a DDI document and optionally execute lint rules.

Parameters:

Name Type Description Default
source DocumentSource

Document payload to validate.

required
include_lint bool

True to execute lint rules in addition to schema validation.

True
lint_rules Sequence[str] | None

Specific lint rule identifiers to run.

None
lint_profile str | None

Named lint profile to execute.

None
raise_error bool

True to raise :class:DDIValidationError when issues are detected.

False
include_context bool

False to omit contextual snippets from reported schema issues.

True
version str | None

DDI schema version to validate against; None uses the version the document declares.

None

Validate a fragment instance and return structured issues.

Parameters:

Name Type Description Default
source FragmentSource

Fragment payload to validate.

required
include_lint bool

True to execute lint rules in addition to schema validation.

True
lint_rules Sequence[str] | None

Specific lint rule identifiers to run.

None
lint_profile str | None

Named lint profile to execute.

None
raise_error bool

True to raise :class:DDIValidationError when issues are detected.

False
include_context bool

False to omit contextual snippets from reported schema issues.

True
version str | None

DDI schema version to validate against; None uses the version the document declares.

None

ValidationReport dataclass

ValidationReport(
    schema_issues: list[SchemaValidationIssue],
    lint_findings: list[LintFinding],
)

Aggregate of schema issues and lint findings produced during validation.

has_errors

has_errors() -> bool

Return True when any message is marked as an error.

has_warnings

has_warnings() -> bool

Return True when any message is marked as a warning.

iter_messages

iter_messages() -> Iterator[ValidationMessage]

Iterate over unified validation messages.

messages

messages() -> list[ValidationMessage]

Return a list of merged validation messages.

to_dict

to_dict(*, include_context: bool = True) -> dict

Return a JSON-serialisable representation of the aggregated result.

ValidationMessage dataclass

ValidationMessage(
    message: str,
    severity: str,
    source: str,
    xpath: str | None = None,
    context: str | None = None,
    location: str | None = None,
    rule_id: str | None = None,
)

Normalized representation of validation feedback for UI consumption.

from_lint_finding classmethod

from_lint_finding(
    finding: LintFinding,
) -> ValidationMessage

Build a message from a :class:LintFinding.

from_schema_issue classmethod

from_schema_issue(
    issue: SchemaValidationIssue,
) -> ValidationMessage

Build a message from a :class:SchemaValidationIssue.

to_dict

to_dict() -> dict

Return a JSON-serialisable representation of the message.

Linting

Execute lint rules against document and return all findings.

Validate and lint document using a named profile.

Update and return the active :class:LintConfiguration.

Only options explicitly provided are modified. allowed_agencies accepts None to disable the built-in agency allow-list and any other sequence to replace it. required_citation_languages expects an iterable of BCP 47 language identifiers that must be present on citation titles.

LintConfiguration dataclass

LintConfiguration(
    allowed_agencies: tuple[str, ...] | None = None,
    require_citation: bool = True,
    require_citation_title: bool = True,
    required_citation_languages: tuple[str, ...] = (),
)

Collection of options governing built-in lint behaviour.

LintFinding dataclass

LintFinding(
    rule_id: str,
    message: str,
    severity: str = "error",
    location: str | None = None,
)

Container describing a single lint finding.

as_dict

as_dict() -> dict[str, str | None]

Return a JSON-serialisable representation of the finding.

Register a linting rule.

target determines whether callback receives the whole :class:DDIDocument or the root :class:Element of the document.

Register a named collection of lint rules.

Exceptions

Standardized exception hierarchy for DDI operations.

All DDI-specific exceptions inherit from DDIError and provide rich context including source location, XPath, and original cause.

Exception Hierarchy

DDIError (base) ├── DDIReadError - File/stream reading failures │ └── DDIParseError - Malformed XML or unexpected elements ├── DDIWriteError - Serialization failures ├── DDIValidationError - Schema validation failures ├── DDIModelError - Model constraint violations │ ├── ModelValidationError - Validation check failures │ ├── ModelBuildError - Builder/construction failures │ └── DuplicateIdentifierError - Identifier already in use (ValueError) └── DDIReferenceError - Reference resolution failures (LookupError)

Warning hierarchy

UserWarning └── DDIReferenceWarning - References to items missing from a saved study

ErrorLocation dataclass

ErrorLocation(
    filename: str | None = None,
    xpath: str | None = None,
    line: int | None = None,
    column: int | None = None,
    element_tag: str | None = None,
)

Structured details describing where a problem originated.

Attributes:

Name Type Description
filename str | None

Source file path, if known.

xpath str | None

XPath to the problematic element, if applicable.

line int | None

Line number in source, if available.

column int | None

Column number in source, if available.

element_tag str | None

Tag name of the problematic element.

Example

loc = ErrorLocation( ... filename="study.xml", line=42, ... xpath="/DDIInstance/StudyUnit", ... ) print(loc.describe()) study.xml:42, xpath /DDIInstance/StudyUnit

describe

describe() -> str | None

Return a human-readable description of this location.

merge

merge(other: ErrorLocation | None) -> ErrorLocation

Combine this location with another, preferring non-None values.

combine classmethod

combine(
    *locations: ErrorLocation | None,
) -> ErrorLocation | None

Combine multiple locations into one.

from_element classmethod

from_element(
    element: Any, *, xpath: str | None = None
) -> ErrorLocation | None

Create location from an XML element.

from_issue classmethod

from_issue(
    issue: SchemaValidationIssue,
) -> ErrorLocation | None

Create location from a schema validation issue.

DDIError

DDIError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
)

Bases: Exception

Base class for all DDI-specific exceptions.

All DDI exceptions provide: - A human-readable message - Optional location information (file, line, xpath) - Optional original cause for exception chaining

Attributes:

Name Type Description
message str

The error message without location info.

location

Structured location information.

original_exception BaseException | None

The underlying cause, if any.

Example

try: ... raise DDIError("Something went wrong", location=ErrorLocation(line=42)) ... except DDIError as e: ... print(e.location.line) 42

message property

message: str

The error message without location information.

original_exception property

original_exception: BaseException | None

The original exception that triggered this error, if any.

with_location

with_location(location: ErrorLocation) -> DDIError

Return a copy of this exception with updated location.

DDIReadError

DDIReadError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
)

Bases: DDIError

Raised when reading a DDI document fails.

This covers file access errors, encoding issues, and other I/O problems during document loading.

DDIParseError

DDIParseError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
    expected_tag: str | None = None,
    actual_tag: str | None = None,
    element: Any | None = None,
)

Bases: DDIReadError

Raised when XML parsing fails.

This covers syntax errors, malformed XML, and structural issues encountered during parsing. It is a :class:DDIReadError, so code that handles read failures also handles malformed input.

Attributes:

Name Type Description
expected_tag

The tag that was expected, if applicable.

actual_tag

The tag that was found, if applicable.

element

The problematic element, if available.

tag_mismatch classmethod

tag_mismatch(
    expected: str, actual: str, element: Any | None = None
) -> DDIParseError

Create error for tag mismatch.

from_parser_error classmethod

from_parser_error(
    error: BaseException,
    *,
    sources: Iterable[object] | None = None,
) -> DDIParseError

Wrap an lxml or stdlib parser error, keeping its line and column.

DDIWriteError

DDIWriteError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
)

Bases: DDIError

Raised when writing/serializing a DDI document fails.

This covers file access errors, encoding issues, and serialization problems during document saving.

DDIValidationError

DDIValidationError(
    message: str,
    *,
    issues: Sequence[SchemaValidationIssue] | None = None,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
)

Bases: DDIError

Raised when schema validation fails.

Attributes:

Name Type Description
issues list[SchemaValidationIssue]

List of individual validation issues found.

Example

try: ... validate(document) ... except DDIValidationError as e: ... for issue in e.issues: ... print(f"{issue.severity}: {issue.message}")

from_schema_error classmethod

from_schema_error(
    error: BaseException,
    *,
    sources: Iterable[object] | None = None,
    fallback_location: ErrorLocation | None = None,
) -> DDIValidationError

Create from a schema validation error.

DDIModelError

DDIModelError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
)

Bases: DDIError

Base class for model-related errors.

Covers issues with model construction, validation, and constraints.

DuplicateIdentifierError

DuplicateIdentifierError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
)

Bases: DDIModelError, ValueError

Raised when an item is added with an identifier already in the document.

ModelValidationError

ModelValidationError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
    model_type: type | None = None,
    field_name: str | None = None,
)

Bases: DDIModelError

Raised when a model instance fails validation checks.

This is raised by MaintainableBase.validate() and related methods when required fields are missing or constraints are violated.

Attributes:

Name Type Description
model_type

The type of model that failed validation.

field_name

The specific field that caused the failure, if applicable.

Example

study = StudyUnit(agency=None, identifier="test", version="1.0") study.validate() ModelValidationError: StudyUnit requires agency when URN is not provided.

missing_field classmethod

missing_field(
    model_type: type,
    field_name: str,
    context: str | None = None,
) -> ModelValidationError

Create error for a missing required field.

invalid_value classmethod

invalid_value(
    model_type: type,
    field_name: str,
    value: Any,
    reason: str | None = None,
) -> ModelValidationError

Create error for an invalid field value.

ModelBuildError

ModelBuildError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
)

Bases: DDIModelError

Raised when model construction via builders fails.

This is raised by builder classes when required configuration is missing or invalid.

DDIReferenceError

DDIReferenceError(
    message: str,
    *,
    cause: BaseException | None = None,
    location: ErrorLocation | None = None,
    reference_urn: str | None = None,
    reference_type: str | None = None,
)

Bases: DDIError, LookupError

Raised when reference resolution fails.

This occurs when a Reference cannot be resolved to its target maintainable within a document.

Attributes:

Name Type Description
reference_urn

The URN that could not be resolved.

reference_type

The type of object being referenced.

unresolved classmethod

unresolved(
    urn: str | None = None,
    identifier: str | None = None,
    type_of_object: str | None = None,
) -> DDIReferenceError

Create error for an unresolved reference.

DDIReferenceWarning

DDIReferenceWarning(records: Sequence[Any])

Bases: UserWarning

Warns that references in a serialized model point at missing items.

One warning is issued per serialization, listing every unresolved reference, so it can be filtered with warnings.filterwarnings by category.

Attributes:

Name Type Description
records

The unresolved references, as :class:~ddi_l.models.base.ReferenceWarning records.

location_from_element

location_from_element(
    element: object, *, xpath: str | None = None
) -> ErrorLocation | None

Create an ErrorLocation from an XML element.

location_from_source

location_from_source(
    source: object,
) -> ErrorLocation | None

Create an ErrorLocation from a source (file path, file object, etc.).

element_xpath

element_xpath(element: object) -> str | None

Extract a simple XPath from an element's tag.

build_error_location

build_error_location(
    *,
    sources: Iterable[object] | None = None,
    element: object | None = None,
    xpath: str | None = None,
    line: int | None = None,
    column: int | None = None,
) -> ErrorLocation | None

Build an ErrorLocation from various sources of information.

Parameters:

Name Type Description Default
sources Iterable[object] | None

File paths or file objects to extract filename from.

None
element object | None

XML element to extract line/column/tag from.

None
xpath str | None

Explicit XPath override.

None
line int | None

Explicit line number override.

None
column int | None

Explicit column number override.

None

Returns:

Type Description
ErrorLocation | None

Combined ErrorLocation, or None if no location info available.