EndfFile

class endf_parserpy.EndfFile(filename, *, parser=None, mode='index', parsed_cache_bytes=67108864, raw_cache_bytes=67108864, on_error='mark', check_edits='eager', verify_source=False)[source]

Lazy, memory-bounded, editable view of a multi-material ENDF file.

The file is indexed on construction (see TapeIndex). Section data is read from disk and parsed only on access and is then held in bounded caches. Materials are addressed by zero-based position:

with EndfFile("tape.endf") as endf_file:
    material = endf_file[0]         # a MaterialView
    section = material[3, 2]        # parsed MF=3/MT=2 section
    material[3, 2] = section        # edit it back in
    endf_file.export("edited.endf")
Parameters:
  • filename (str or os.PathLike) – Path to the ENDF file.

  • parser (EndfParserBase, optional) – Engine used to parse and write sections. Defaults to EndfParserFactory.create(select="fastest").

  • mode ({"index", "load_raw", "parse_all"}) – "index" (default) only builds the index. "load_raw" also pre-reads section text into the raw cache; "parse_all" also parses every section. The cache budgets still apply, so these modes pre-warm the caches rather than guarantee residency.

  • parsed_cache_bytes (int) – Budgets, in raw-text-equivalent bytes, for the parsed-section and raw-text caches.

  • raw_cache_bytes (int) – Budgets, in raw-text-equivalent bytes, for the parsed-section and raw-text caches.

  • on_error ({"raise", "mark"}) – Whether a section that fails to parse raises SectionParseError or is returned as a FailedSection.

  • check_edits ({"eager", "deferred"}) – When the recipe-conformity of an edited section is checked. "eager" (the default) renders every edited section through the parser’s writer immediately, so a malformed edit raises at the offending assignment, and a retrieved section is a read-only (frozen) view. "deferred" accepts every edit, marking the section dirty, and checks conformity only at export() / to_string() or invalid_edits(); a retrieved section is then a live write-through view.

  • verify_source (bool) – If true, the file’s size and mtime are checked against the index before every disk read; a change raises StaleSourceError.

Notes

An EndfFile is not safe for concurrent use from several threads: its caches, material list and edit overlays are plain, unguarded state, so any access racing with another is undefined. Use one EndfFile per thread.

append_material(material, *, mat, za=None, awr=None)[source]

Append a new material to the tape.

Parameters:
  • material (Mapping) – A nested {MF: {MT: section}} mapping, as returned by an ordinary parsefile. The MF=0 tape-head entry, if present, is ignored.

  • mat (int) – ENDF MAT number of the new material.

  • za (optional) – Identifiers, used by by_za() and the index.

  • awr (optional) – Identifiers, used by by_za() and the index.

Returns:

A view of the appended material.

Return type:

MaterialView

Notes

Under check_edits="eager" every section of the appended material is render-checked immediately, exactly as a section assignment is, so a malformed section is rejected here rather than at export() time.

The mat argument must agree with the MAT number the material carries in its own records (the 'MAT' key of a parsed section, or the control field of a raw section’s first line); a mismatch is rejected, since the records, not the argument, are what gets written to the tape.

build_index(section_path, *, name=None)[source]

Build a secondary index over one or several section fields.

With a single section path – a string "MF/MT[/field...]" – this parses that section of every material that has it, reads the value at the field path and returns a dict {value: [positions]}.

With a list (or tuple) of section paths it builds a composite index instead: the key is the tuple of the values at the respective paths, in the order given, so the result is a dict {(value0, value1, ...): [positions]}. A material is indexed only if every path resolves for it; one that lacks any of the addressed sections or fields is skipped. Paths that share an MF/MT section have it parsed only once per material. The key shape follows the argument type: a one-element list still yields one-element-tuple keys.

One section is parsed per material per distinct MF/MT, so the cost grows with the number of materials. With name the result is also stored and reachable via secondary_indexes; because the index is keyed by tape position, a stored index is dropped whenever a material is appended, removed or reordered, and must then be rebuilt.

by_mat(mat, *, occurrence=None)[source]

Return the material with the given MAT number.

occurrence (zero-based) selects among several materials that share a MAT number, as on a PENDF tape. Without it, a MAT number that is not unique raises AmbiguousMaterialError.

by_za(za)[source]

Return a list of materials with the given ZA identifier.

property cache_nbytes

The current (raw, parsed) cache sizes in bytes.

export(path, *, overwrite=False)[source]

Write the (possibly edited) tape to a file.

The tape is written one material at a time via a temporary file and an atomic replace, so peak memory stays bounded by a single material regardless of the tape size. Untouched sections keep their data records verbatim from disk (they are not parsed) and edited or added sections are rendered by the parser; the SEND/FEND/MEND framing and the column 76-80 sequence numbers are regenerated either way, preserving every data field byte-for-byte without making the tape byte-identical. An existing file is only overwritten when overwrite=True. A tape from which every material has been deleted is written as its tape head (TPID) followed by the tape end (TEND).

Exporting onto the file the EndfFile was opened from is permitted, but it leaves the in-memory structural index stale (the byte offsets of untouched sections have moved). The object is therefore invalidated: every subsequent operation raises StaleSourceError, and the file must be re-opened with a new EndfFile to continue. Exporting to any other path leaves the object usable.

find(*, mat=None, za=None)[source]

Return a list of materials matching every given criterion.

This is the structural lookup; a criterion left as None is not applied. For lookups by a parsed section field, see query().

get(path)[source]

Return the material, section or field addressed by path.

path is an EndfMaterialPath or a string of the form material[/MF/MT[/field...]]. This is the explicit-method synonym of endf_file[path]: a material-depth path yields a MaterialView, a section-depth path a section view (see endf_parserpy.tape.views) and a field-depth path the value at that field. If the addressed section cannot be parsed a SectionParseError is raised regardless of on_error.

property index

The underlying TapeIndex (describes the file on disk).

invalid_edits()[source]

Return the edited sections that do not conform to their recipe.

Renders every edited section through the parser’s writer and returns a list of (position, MF, MT, exception) tuples, one per edited section that fails to render; an empty list means every edit is conformant, so if not endf_file.invalid_edits() reads as “every edit is valid”. Untouched sections are written verbatim and are not checked.

Under check_edits="deferred" this is the explicit conformity check that export() and to_string() perform implicitly; under "eager" every edit was already checked at write time, so it is a near no-op but remains harmless to call.

materials()[source]

Return all materials as a list of MaterialView objects.

property parser

The parser engine used for sections.

query(section_path, value=<object object>, *, predicate=None, tol=0.0)[source]

Return the materials whose section field matches.

Pass exactly one of value (equality, within tol for numbers) or predicate (a callable applied to the field). Returns a list of MaterialView.

reorder(order)[source]

Reorder the materials of the tape.

order is a permutation of range(len(self)): the material currently at order[i] moves to position i.

property secondary_indexes

The named secondary indexes built by build_index().

Emptied whenever a material is appended, removed or reordered, since the indexes are keyed by tape position.

to_string()[source]

Return the (possibly edited) tape as an ENDF-6 formatted string.

Untouched sections keep their data records verbatim from disk and edited or added sections are rendered by the parser; in both cases the SEND/FEND/MEND framing and the column 76-80 sequence numbers are regenerated, so every data field is preserved byte-for-byte but the tape is not necessarily byte-identical to the input. The result ends with a newline; use str.splitlines() if a list of lines is needed. A tape from which every material has been deleted is written as its tape head (TPID) followed by the tape end (TEND).

This necessarily builds the whole tape in memory; for a large tape, write it to a file with export(), which is memory-bounded.

unload(position=None)[source]

Drop cached raw text and parsed sections.

Edits held in the material overlays are not affected. With no argument the whole cache is cleared; given a material position, only that material’s cached data is dropped.

class endf_parserpy.tape.FailedSection(exception, raw_lines, position, mf, mt)[source]

Internal placeholder for a section that could not be parsed.

When the EndfFile was opened with on_error="mark" a section that fails to parse is kept as a FailedSection so that the bulk operations (query(), build_index(), export()) can skip it or write it back verbatim instead of aborting. Accessing such a section directly (endf_file[path] or material[mf, mt]) raises SectionParseError, with this object’s exception kept as the cause; a FailedSection is therefore never handed back to the caller.

exception

The exception raised while parsing the section.

Type:

Exception

raw_lines

The raw text of the section.

Type:

list[str]

position

Position of the material the section belongs to.

Type:

int

mf, mt

The MF/MT numbers of the section.

Type:

int