Release notes¶
Unreleased¶
OEM producer compatibility¶
OEM 1.0 accepts comments between header and metadata assignments, between segments, and after the final record. Comments between ephemeris records remain invalid. Comment text is retained in the corresponding model block.
OEM 2.0 and 3.0 accept header comments between header assignments. All OEM KVN readers accept comments between metadata assignments and unique header and metadata assignments in any order; duplicate keywords and a version line anywhere but first remain errors. OEM XML accepts unique header and metadata children in any order. OEM 1.0 accepts mixed-case book-listed text values.
The shared XML reader accepts equivalent UTF-8 XML 1.0 declarations and omission of an unused schema-instance namespace. Used prefixes still need valid declarations; generated XML keeps the standard declaration and namespaces.
OEM KVN ignores trailing ASCII spaces when checking the input line-length limit, including on comments. Generated lines still fit the 254-character limit.
OEM KVN reads comments between a covariance epoch or frame and its first numeric row into that matrix. XML preserves them; KVN writing still rejects comments on later matrices when their association cannot be retained.
OEM KVN reads complete covariance matrices without section markers when an
EPOCHfollows the state records; generated KVN writes the standard markers.XML deserialization errors name a nearby source line and column.
Python threading and parsing fixes¶
Python parsing, validation, generation, conversion and file I/O now release the GIL while the Rust core runs, so other Python threads keep running. Building and reading Python objects still holds it.
KVN version lines (
CCSDS_xxx_VERS) and APMEPOCHreject a bracketed unit instead of silently dropping it, in every family.OEM segments whose XML TIME_SYSTEM differs only by surrounding whitespace, such as
UTCpadded with spaces, now count as one time system. The original text is kept.XML output writes unit-bearing values of very large or very small magnitude in exponent form (
1e+308instead of 309 digits); every value still reads back exactly.Passing a NumPy array with the wrong number of dimensions now raises
ValueErrornaming the input and its shape, instead ofTypeError: 'ndarray' object is not an instance of 'ndarray'.A malformed KVN time tag is now a located KVN syntax error (
parse.kvn.syntaxwith line and column) in every family, like a malformed number, instead of an unlocated epoch error.OEM metadata errors report real field paths (for example
metadata.start_time) instead of names derived from the message text.OEM useable spans are checked for real overlap: segments no longer have to be in time order, and only complete spans are compared.
OEM KVN rejects a second covariance
EPOCHbefore its matrix, naming that line.OEM KVN generation no longer allocates per covariance matrix when
COV_REF_FRAMEis set.OEM XML output no longer writes
unitsattributes on state and covariance values. The schema makes them optional and each value has a single fixed unit, so the output is smaller and parsing it back needs no per-value allocations. Input withunitsis still accepted and checked.Python: a wrong element type in a record list raises
TypeErrorinstead ofValueError(breaking). Reading a file of another family raisesNdmUnsupportedMessageErrornaming the file instead ofValueError(breaking). Epoch strings rejected by constructors and setters raiseNdmEpochError, still aValueError.NdmIoErrorcarrieserrnoandfilename(andfilename2forconvert_file).
Book-aligned OEM and XML parsing (breaking change)¶
OEM parsing and validation now take their rules from CCSDS 502.0-B-3 and the NDM/XML books and schemas rather than project policy; the remaining limits are listed in the OEM conformance inventory. Newly accepted:
KVN blank lines anywhere, trailing blanks after
META_STARTand the covariance markers, empty optional values, and an empty covariance section.Overlapping total spans without useable bounds, object names differing only in case, covariance matrices with equal epochs, and MET/MRT durations (including
REF_FRAME_EPOCH, now a time-system-dependentEpoch) such as0000-000T00:10:00.XML namespace declarations and schema-location hints on any element of a standalone message (ODM 8.12.7 still limits combined constituents to
idandversion), the qualified (ndm:-prefixed) element form in every family, andINF/-INF/NaNOEM state and covariance values in XML.Mixed calendar and day-of-year epochs with different fractional precision now compare correctly in OEM, AEM and OCM.
Newly rejected:
XML documents in every family without an XML 1.0 declaration, with a non-UTF-8 encoding, or with an undeclared prefix used in a schema hint.
OEM KVN covariance rows of the wrong width, and mixed-case KVN spellings of the time systems and reference frames listed by the 2.0 and 3.0 books (for example
UtcorEme2000). OEM 1.0 accepts these spellings. XML text followsxsd:string, so such XML values are accepted and only their conversion to KVN fails; ICD-defined values keep their spelling in both notations.Time tags with more than 16 fractional-second digits, in every family except TDM (ODM 7.5.10 and the matching ADM, CDM and RDM rules).
Empty or
n/aXML values for optional numbers, epochs and enumerations in every family, which were silently treated as absent; the schema types do not allow them. Optional XML strings keepn/aand empty text literally. A malformed optional value can no longer silently drop itsunitsattribute.XML special values spelled other than
INF,-INForNaN(for exampleinfor+INF), in every family.OPM
nilandxsi:nilattributes, which the OPM schema does not allow.
OEM review follow-up:
Shared XML parsing rejects literal
]]>in text, empty prefixed namespace bindings, duplicate schema-location attributes hidden behind prefix aliases, and empty or reservedxmlprocessing-instruction targets.OEM 3.0 and OEM 2.0 are now Verified in the support matrix. OEM 2.0 is reviewed against 502.0-B-2 with Corrigendum 1 and its schema; it differs from 3.0 in the header, and two looser readings (text case,
-0/special values) are documented. Every shipped OEM example is checked as 2.0. ODM 5.2.4.7 (enough records for the interpolation method) is recorded as a requirement the book leaves undefined rather than a conformance gap.OEM 1.0 is parse-only, like OPM 1.0: it shares the 2.0 model and cannot be written. XML is rejected for 1.0, a KVN-only format, and so is content that 502.0-B-1 does not have (
CLASSIFICATION,MESSAGE_ID,REF_FRAME_EPOCH, accelerations, covariance). Some valid 1.0 files are still rejected; the OEM conformance page lists them.OEM covariance epochs are no longer required to fall inside the segment’s
START_TIME/STOP_TIME: table 5-3 says they should, but the book’s own example G-14 does not, so the shippedoem_g14.xmlis now the example as published. State epochs are still bounded.OEM and AEM KVN numbers outside the double range (ODM 7.5.7e) are rejected instead of becoming infinity or zero.
AEM KVN history numbers get the same reading as OEM: any number of digits and integer-form values of any size.
OEM KVN reading accepts an unterminated last line and ephemeris and covariance numbers with more than 16 digits (such as the 17-digit shortest spelling of a double) or integers outside the 32-bit range. These break clear book rules but are common and lose nothing; writing still follows the book and rounds numbers to 16 significant digits.
OEM KVN generation rejects an empty
INTERPOLATIONorCOV_REF_FRAME, which KVN would read back as absent; converting an XML<INTERPOLATION/>to KVN now fails instead of dropping it.Python: the NumPy inputs of OEM, AEM and CDM accept integer arrays and nested lists, converting them to float, instead of raising a confusing
TypeError.Python (breaking):
OemData,OemData.from_numpy,OmmData,CdmData,CdmData.from_numpy,CdmStateVectorandStateVectortakecomment=instead ofcomments=, matching theircommentattribute and the other families.CombinedNdmkeepscomments=, the name of its attribute.An OEM KVN covariance section holding only comments is accepted; its comments join the data comments.
An empty OEM KVN
COV_REF_FRAMEis absent, like other empty optional values.Mixed-case
RSW,RTNandTNW(ODM 3.2.4.11) are rejected in OEM KVNCOV_REF_FRAME.KVN syntax errors in every family carry their reason as the message instead of an empty message.
Python: assigning an empty snapshot back to an empty
OemDatais a no-op instead of an error.Python: setting
x_ddot,y_ddotorz_ddoton aStateVectorAcckeeps explicit XML units, like assigningstate_vector_numpy.Where the CCSDS books are unclear or conflict, parsing takes the permissive reading; OEM’s remaining strict choices are listed in its conformance document.
Generated XML now declares xmlns:xsi and xmlns:ndm on the root and
writes special values as INF, -INF and NaN. KVN comments drop
trailing blanks, which the book makes insignificant.
Python docstrings now carry the CCSDS book reference of every field whose core documentation has one.
Earlier OEM corrections in this release: KVN interpolation degrees accept a leading plus and must
fit a positive signed 32-bit integer; malformed optional OEM XML numbers and
epochs raise errors instead of being treated as absent; OEM optional strings and
shared ODM header strings retain literal content, including n/a; shared XML
parsing rejects mixed container text, invalid character references and
malformed comments.
Python binding corrections (breaking change)¶
validate() on OemSegment, OemMetadata, OemData, AemSegment,
AemMetadata, AemData, AcmSegment, AcmMetadata and AcmData
now raises NdmValidationError, like message-level validate(), instead of
ValueError. NdmValidationError is not a ValueError subclass.
OemCovarianceMatrix(epoch, values, cov_ref_frame=None, comment=None) makes
the last two arguments optional. A wrong-typed element in a repeated field now
reports "<field>[<index>] must be <Type>" in every family.
AemData.attitude_states_numpy assignment no longer partially writes when a
later element is invalid. The OEM NumPy setters update existing records in
place, keeping record identity, covariance frames and comments, and units, and
write nothing if any element is invalid. Covariance metadata supplied without
covariance epochs and values raises ValueError instead of being discarded.
Rust parsing controls (breaking change)¶
ParseOptions and the from_str_with_options, from_file_with_options,
convert_with_options, and convert_file_with_options functions have been
removed. Use from_str/from_file or their *_with_notation variants,
and use convert/convert_file for conversion. Applications that need
input-size or record-count limits should enforce them before parsing; XML depth
remains protected by the library’s fixed safety limit.
Python metadata construction (breaking change)¶
Metadata constructors now require explicit interpretation fields instead of silently supplying defaults:
AemMetadatarequiresref_frame_a,ref_frame_b,start_time,stop_time, andtime_system.OemMetadatarequirescenter_name,ref_frame, andtime_system.OmmMetadataandOpmMetadatarequirecenter_name,ref_frame, andtime_system.RdmMetadatarequirescenter_nameandtime_system.AcmMetadata,ApmMetadata,OcmMetadata, andTdmMetadatarequiretime_system.
Calls omitting these arguments now raise TypeError. Pass the values appropriate
to your message explicitly; keyword arguments make the intended fields clear.
interpolation_degree=0 is now rejected instead of being treated as absent.
Use None to omit the degree, or a positive integer when specifying it.
See Common Workflows for metadata construction guidance.
AemData and AemData.from_numpy now require an explicit
attitude_type instead of inferring it from unambiguous row widths.
OemData names its optional covariance collection covariance_matrices;
the mutable model property remains covariance_matrix.