ndf-parse#

Submodules:

This package is designed for prcessing Eugen Systems ndf files. It allows for easier code manipulations than out-of-the-box differ for Eugen mods.

convert(data: str | bytes, ensure_no_errors: bool = True) List#

Converts string/byte data to a List object. Should be used to parse ndf files as a whole.

Parameters:
  • data (str | bytes) – ndf code to parse.

  • ensure_no_errors (bool, default=True) – If True then fail if ndf code contains syntax errors. Be mindful of checking strictness.

Returns:

Model representation of a file.

Return type:

List

expression(data: str | bytes, ensure_no_errors: bool = True) Dict[str, Any]#

Converts string/byte data to a an expression wrapped in a dict. Should be used to parse individual expressions for further injection into an existing model.

Parameters:
  • data (str | bytes) – ndf code to parse.

  • ensure_no_errors (bool, optional, default=True) – If True then fail if ndf code contains syntax errors. Be mindful of checking strictness.

Returns:

A dict containing an item along with possible extra row attributes.

Return type:

DictWrapped

Examples

>>> import ndf_parse as ndf
>>> src = '''Obj is Typ(
...     Memb1 = "SomeStr"
...     Memb2 = 12
... )'''
>>> source = ndf.convert(src)
>>> arg = ndf.expression("export A is 12")
>>> arg
{'value': '12', 'namespace': 'A', 'visibility': 'export'}
>>> source.add(**arg)  # ** will deconstruct dict into method's parameters
ListRow[1](value='12', visibility='export', namespace='A')
>>> memb = ndf.expression("Memb3 = [1,2,3,Obj2(Memb1 = 5)]")
>>> memb
{'value': List[ListRow[0](value='1', visibility=None, namespace=None),
ListRow[1](value='2', visibility=None, namespace=None),
ListRow[2](value='3', visibility=None, namespace=None),
ListRow[3](value=Object[MemberRow[0](value='5', member='Memb1',
type=None, visibility=None, namespace=None)], visibility=None,
namespace=None)], 'member': 'Memb3'}
>>> source[0].value.add(**memb)
MemberRow[2](value=List[ListRow[0](value='1', visibility=None, namespace=None),
ListRow[1](value='2', visibility=None, namespace=None),
ListRow[2](value='3', visibility=None, namespace=None),
ListRow[3](value=Object[MemberRow[0](value='5', member='Memb1', type=None,
visibility=None, namespace=None)], visibility=None, namespace=None)],
member='Memb3', type=None, visibility=None, namespace=None)
>>> ndf.printer.print(source)
Obj is Typ
(
    Memb1 = "SomeStr"
    Memb2 = 12
    Memb3 =
    [
        1,
        2,
        3,
        Obj2
        (
            Memb1 = 5
        )
    ]
)
export A is 12
expressions(data: str | bytes, ensure_no_errors: bool = True) List[Dict[str, Any]]#

Same as expression(), only outputs a list of expressions instead of only the first one.

datastr | bytes

ndf code to parse.

ensure_no_errorsbool, optional, default=True

If True then fail if ndf code contains syntax errors. Be mindful of checking strictness.

Returns:

A list of dict items containing expressions with additional data.

Return type:

list[DictWrapped]

walk(item, condition) Iterator#

Recursively walks a model representation of an ndf file.

Parameters:
  • item (str | DeclarationsList | DeclListRow) – Source to walk.

  • condition (Callable[[Any], bool]) –

    Function that is responsible for filtering items. Should return True if an item matches desired criteria.

    Note

    This function can accept multiple types so it’s a user’s responsibility to validate the item.

Yields:

str | DeclarationsList | DeclListRow – Items that match the condition criteria (i.e. on which the condition returns True).

Examples

Usage of this function is covered here

class Mod(mod_src: str, mod_dst: str)#

This class holds links to source and destination mods. It also holds methods and wrappers designed to streamline editing, mainly the edit() method.

mod_src#

Path to an unedited source mod. Can be relative to CWD.

Type:

str

mod_dst#

Path to a generated destination mod. Can be relative to CWD.

Type:

str

edits#

List of current edits. It tracks nested edit() calls and should not be edited by hand.

Type:

list[Edit]

current_edit#

Currently active edit. In fact this is an alias to Mod.edits[-1], i.e. it’s an edit at the top of the stack.

Type:

Edit | None

current_tree#

Tree (a model representation of an ndf file) attribute of a currently active edit.

Type:

model.List | None

Note

Paths are relative to an execution path, more on that here.

Examples

>>> import ndf_parse as ndf
>>> mod = ndf.Mod('path/to/unedited/mod', 'path/to/generated/mod')
>>> with mod.edit('GameData/path/to/file.ndf') as source:
...     ...  # edits to the source
>>> # at the end of `with` file gets automatically written out
None
edit(file_path: str, save: bool = True, ensure_no_errors: bool = True) Mod#

Creates a new edit. It is designed to work with with clause. Avoid using it outside of the with unless you know what you are doing.

Parameters:
  • file_path (str) – File to be edited. Path should be relative to a mod root, i.e. GameData/Generated/..., more on that here.

  • save (bool, default=True) – If True then file gets written out at the end of the with statement.

  • ensure_no_errors (bool, default=True) – Ensures that original ndf code has no syntax errors. Fails if there are any and this parameter is True. Be mindful of checking strictness.

Returns:

Returns it’s parent Mod object. Required for with statement to work correctly.

Return type:

Mod

write_edit(edit: Edit, force: bool = True) bool#

Write given edit to the destination. Return True if data was written out.

An example of writing a bunch of edits if context manager (with statement) was not used:

>>> import ndf_parse as ndf
>>> mod = ndf.Mod('path/to/unedited/mod', 'path/to/generated/mod')
>>> # load sources to be edited
>>> ammo_src = Mod.edit('GameData/../Ammunition.ndf').current_tree
>>> unit_src = Mod.edit('GameData/../UniteDescriptor.ndf').current_tree
>>> # load decks for reference only, no need to write out later
>>> decks_src = Mod.edit('GameData/../Decks.ndf', False).current_tree
>>> ...  # do stuff here
>>> for edit in mod.edits:
>>>     mod.write_edit(edit, False)  # disabled forced write so it
>>>                                  # does not write `decks_src` out
Parameters:
  • edit (Edit) – An edit to write out to the destination mod.

  • force (bool , default=True) – If True (default) then ignores Edit.save property of the edit and writes out always.

Return type:

True if file was written out, False otherwise.

check_if_src_is_newer() bool#

Nukes the destination mod and recreates a pristine copy of the destination mod if the source mod is newer (if modification date of the source is newer than of the destination).

Returns:

True if the destination mod was rebuilt.

Return type:

bool

update_dst()#

Forcefully rebuilds a clean version of the destination mod, no checks performed.

Warning

Must be used before any edits are applied otherwise they will be overwritten by data from source.

parse_src(file_path: str, ensure_no_errors: bool = True) List#

Parses a file from a source mod.

This function does not write any modified data back to a destination file. It’s merely a convenience function for retrieving another mod file model to fetch some data without risking to write any modifications back out.

Parameters:
  • file_path (str) – Relative path to a source file. Path should be relative to a mod root, i.e. GameData/Generated/..., more on that here.

  • ensure_no_errors (bool, optional, default=True) – If on then fails in case there are any syntactic errors in the ndf code. Be mindful of checking strictness.

Returns:

Model representation of the source mod file.

Return type:

List

Examples

>>> import ndf_parse as ndf
>>> mod = ndf.Mod('path/to/unedited/mod', 'path/to/generated/mod')
>>> with mod.edit('GameData/path/to/units_file.ndf') as units:
...     # This is a pseudocode, it does not match an actual mod
...     # structure, it's intended to only show a possible use case.
...     # We up the speed for any unit that has a 155mm weapon.
...     weapons = mod.parse_src('GameData/path/to/weapons_file.ndf')
...     for unit_row in units:
...         weapon_class = unit_row.value.by_member('WeaponClass').value
...         weapon_row = weapons.by_namespace(weapon_class)
...         if weapon_row.value.by_member('Caliber').value == '155':
...             unit = unit_row.value
...             speed_row = unit.by_member('Speed')
...             speed_row.value += ' * 2'
parse_dst(file_path: str, ensure_no_errors: bool = True) List#

Parses a file from a destination mod.

This function is identical to parse_src() in it’s functionality and intent.

Parameters:
  • file_path (str) – Relative path to a destination file. Path should be relative to a mod root, i.e. GameData/Generated/..., more on that here.

  • ensure_no_errors (bool, optional, default=True) – If on then fails in case there are any syntactic errors in the ndf code. Be mindful of checking strictness.

Returns:

Model representation of the source mod file.

Return type:

List

class Edit(tree: List, file_path: str, save: bool)#

Holds data about currently edited file.

tree#

Model of a currently edited tree.

Type:

List

file_path#

Relative path to a destination file. Path should be relative to a mod root, i.e. GameData/Generated/..., more on that here.

Type:

str

save#

Whether to write out the file after edits are done or not.

Type:

bool