Utilities for parsing an existing trade list

parse_give_command(command, name, **kwargs)

Parse a /give command (such as you'd find from a skin lookup site) to extract just the relevant specification that needs to go into the head-list

Parameters:

Name Type Description Default
command str

The full /give command

required
name str

The display name to give to the head

required
**kwargs

Any customizations (color, formatting, note block sound) to give to the head. See: HeadSpec

{}

Returns:

Type Description
HeadSpec

The tokenized head specification

Raises:

Type Description
ValueError

If the command could not be parsed

Source code in head_hunter/parse.py
def parse_give_command(command: str, name: str, **kwargs) -> HeadSpec:
    """Parse a /give command (such as you'd find from a skin lookup site) to
    extract just the relevant specification that needs to go into the head-list

    Parameters
    ----------
    command : str
        The full `/give` command
    name : str
        The display name to give to the head
    **kwargs
        Any customizations (color, formatting, note block sound) to give
        to the head. See: `HeadSpec`

    Returns
    -------
    HeadSpec
        The tokenized head specification

    Raises
    ------
    ValueError
        If the command could not be parsed
    """
    if "player_head[" in command:
        base_head = _parse_give_v41(command)
    elif "player_head{" in command:
        base_head = _parse_give_v4(command)
    else:
        raise ValueError("Could not parse command:\n" + command)

    return HeadSpec(name, **{base_head[0]: base_head[1]}, **kwargs)  # type: ignore

parse_mob_heads(mob)

Extract head specs from a "More Mob Heads" data pack loot table.

Parameters:

Name Type Description Default
mob str | PathLike

Either the name of the mob whose head (or heads) you're looking to parse (in which case this method will attempt to extract the mob head from a "more mob heads" data pack stored in the "packs" folder)

or

the path of the particular loot table JSON you're wanting to parse

required

Returns:

Type Description
List of HeadSpec

list of player-head specifications such that calling

/give @s minecraft:player_head{head.spec}
would give you the specified head

Raises:

Type Description
FileNotFoundError

If the specified file doesn't exist or can't be found

PermissionError

If you don't have the ability to open the file

JSONDecodeError

If the specified file is not valid JSON

Source code in head_hunter/parse.py
def parse_mob_heads(mob: str | PathLike) -> list[HeadSpec]:
    """Extract head specs from a "More Mob Heads" data pack loot table.

    Parameters
    ----------
    mob: str or path
        Either the name of the mob whose head (or heads) you're looking
        to parse (in which case this method will attempt to extract the mob
        head from a "more mob heads" data pack stored in the "packs" folder)

        _or_

        the path of the particular loot table JSON you're wanting to parse

    Returns
    -------
    List of HeadSpec
        list of player-head specifications such that calling
        ```
        /give @s minecraft:player_head{head.spec}
        ```
        would give you the specified head

    Raises
    ------
    FileNotFoundError
        If the specified file doesn't exist or can't be found
    PermissionError
        If you don't have the ability to open the file
    JSONDecodeError
        If the specified file is not valid JSON
    """
    # first check if it's a file
    try:
        with open(mob) as mob_file:
            return _parse_mob_heads(mob_file)
    except (FileNotFoundError, PermissionError, json.JSONDecodeError) as oops:
        # maybe it's a relative path inside a pack?
        try:
            with file_from_data_pack("more mob heads", mob) as mob_file:
                return _parse_mob_heads(mob_file)
        except (KeyError, json.JSONDecodeError, PermissionError):
            pass
        if not isinstance(mob, str):
            raise oops

    # now check if it's the mob name

    for namespace, loot_table_dir in (
        ("more_mob_heads", "loot_table"),
        ("minecraft", "loot_table"),
        ("minecraft", "loot_tables"),
    ):
        try:
            with file_from_data_pack(
                "more mob heads",
                Path("data") / namespace / loot_table_dir / "entities" / f"{mob}.json",
            ) as mob_file:
                return _parse_mob_heads(mob_file)
        except KeyError:
            continue
    else:
        raise FileNotFoundError(f"Could not find a loot table for {mob}")

parse_wandering_trades(trade_path=None)

Parse an existing trade list

Parameters:

Name Type Description Default
trade_path path

The trade list you want to parse. If None is specified, this method will look for a "wandering trades" pack in the packs folder and attempt to parse add_trade.mcfunction from there.

None

Returns:

Type Description
list of HeadSpec

list of player-head specifications such that calling

/give @s minecraft:player_head{head.spec}
would give you the specified head

list of str

list of block trade commands, with the trade index replaced by the placeholder "IDX"

Raises:

Type Description
FileNotFoundError

If the specified trade file doesn't exist

PermissionError

If you don't have the ability to open the trade file

RuntimeError

If a command in the file could not be parsed

Notes

This function is not smart enough to detect if the full spec doesn't actually match the "skull owner"

Source code in head_hunter/parse.py
def parse_wandering_trades(
    trade_path: str | PathLike | None = None,
) -> tuple[list[HeadSpec], list[str]]:
    """Parse an existing trade list

    Parameters
    ----------
    trade_path : path, optional
        The trade list you want to parse. If None is specified,
        this method will look for a "wandering trades" pack in the packs folder
        and attempt to parse `add_trade.mcfunction`  from there.

    Returns
    -------
    list of HeadSpec
        list of player-head specifications such that calling
        ```
        /give @s minecraft:player_head{head.spec}
        ```
        would give you the specified head
    list of str
        list of block trade commands, with the trade index replaced by the
        placeholder "IDX"

    Raises
    ------
    FileNotFoundError
        If the specified trade file doesn't exist
    PermissionError
        If you don't have the ability to open the trade file
    RuntimeError
        If a command in the file could not be parsed

    Notes
    -----
    This function is not smart enough to detect if the full spec doesn't
    actually match the "skull owner"
    """
    if trade_path is None:
        with file_from_data_pack(
            "wandering trades hermit edition",
            (
                function_folder / HEAD_TRADE_FILENAME
                for function_folder in _function_dirs(Path("data") / "wandering_trades")
            ),
        ) as trade_file:
            return _parse_wandering_trades(trade_file)
    else:
        with open(trade_path) as trade_file:
            return _parse_wandering_trades(trade_file)