semantics Package

semantics Package

Modules relating to NBT semantics

The modules in this package provide intermediate constructs to simplify working with NBT. Their primary purpose is making nbtparse.minecraft modules less repetitive and easier to understand.

Nothing in this package directly relates to Minecraft itself, however, so you may find uses for it in other contexts.

fields Module

A field is part of a TAG_Compound that corresponds to a top-level tag.

It knows how to translate a tag or group of tags into a Pythonic value and back again, and uses the descriptor protocol to make this translation seamless.

Typical usage would be something like this:

class FooFile(NBTFile):
    bar = LongField(u'Bar')

Thereafter, when saving or loading a FooFile, the top-level TAG_Long called Bar will be accessible under the attribute bar. The NBT version is still accessible under the FooFile.data attribute (or by calling the to_nbt() method, which is usually more correct).

Fields are a thin abstraction over the data dict in an NBTObject; modifying the dict may cause Fields to misbehave.

Idea shamelessly stolen from Django, but massively simplified.

class nbtparse.semantics.fields.AbstractField(*args, default=None, **kwargs)[source]

Bases: object

Root of the Field class hierarchy.

attach(owner: 'nbtparse.semantics.nbtobject.NBTMeta')[source]

Hook called on fields declared within a given class.

Does nothing by default.

default = None

Default value used by set_default().

delete_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]
get_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str) → object[source]
load(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]

Hook called during from_nbt().

Does nothing by default.

save(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]

Hook called during to_nbt().

Does nothing by default.

set_default(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]

Reset this field to its “default” value.

Useful when constructing an NBTObject.

set_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str, value: object)[source]
class nbtparse.semantics.fields.BooleanField(nbt_name: str, *, default: bool=False)[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_Byte acting as a boolean.

static from_python(value: bool) → nbtparse.syntax.tags.ByteTag[source]
static to_python(tag: nbtparse.syntax.tags.ByteTag) → bool[source]
class nbtparse.semantics.fields.ByteArrayField(nbt_name: str, *, default: bytearray=None)[source]

Bases: nbtparse.semantics.fields.MutableField, nbtparse.semantics.fields.SingleField

Field for a TAG_Byte_Array.

static from_python(value: bytearray) → nbtparse.syntax.tags.ByteArrayTag[source]
static to_python(tag: nbtparse.syntax.tags.ByteArrayTag) → bytearray[source]
class nbtparse.semantics.fields.ByteField(nbt_name: str, *, default: int=0)[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_Byte acting as an integer.

static from_python(value: int) → nbtparse.syntax.tags.ByteTag[source]
static to_python(tag: nbtparse.syntax.tags.ByteTag) → int[source]
class nbtparse.semantics.fields.DoubleField(nbt_name: str, *, default: float=0.0)[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_Double.

static from_python(value: int) → nbtparse.syntax.tags.DoubleTag[source]
static to_python(tag: nbtparse.syntax.tags.DoubleTag) → int[source]
class nbtparse.semantics.fields.EnumField(nbt_name: str, enum_class: enum.EnumMeta, *, tag_type: type=<class 'nbtparse.syntax.tags.IntTag'>, default: enum.Enum=None)[source]

Bases: nbtparse.semantics.fields.SingleField

Field for an enumerated type.

See enum.

from_python(enum_value: enum.Enum) → nbtparse.syntax.tags.AbstractTag[source]
to_python(number: nbtparse.syntax.tags.AbstractTag) → enum.Enum[source]
class nbtparse.semantics.fields.FloatField(nbt_name: str, *, default: float=0.0)[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_Float.

static from_python(value: int) → nbtparse.syntax.tags.FloatTag[source]
static to_python(tag: nbtparse.syntax.tags.FloatTag) → int[source]
class nbtparse.semantics.fields.HeterogenousDictField(nbt_name: str, schema: {<class 'str'>: <class 'nbtparse.semantics.fields.AbstractField'>}, *, default: {<class 'str'>: <class 'object'>}=None)[source]

Bases: nbtparse.semantics.fields.MutableField, nbtparse.semantics.fields.SingleField

Field for a dictionary of heterogenous values.

Keys are strings, values are arbitrary objects. The key 'data' is reserved for storing the original value of the NBT. None of the keys may begin with underscores.

from_python(mapping: {<class 'str'>: <class 'object'>}) → nbtparse.syntax.tags.CompoundTag[source]
schema = None

Template for the dictionaries this field should create.

The keys are arbitrary strings, which will be duplicated verbatim. Those strings must not begin with underscores. The values are fields, which will be invoked in the normal manner to create the values of this dictionary, and to parse them when converting back to NBT.

The original NBT will be stored in the 'data' key, which is reserved for this purpose. If the key still exists when converting back to NBT, it will be used to supply any values not specified elsewhere in the dictionary. This allows round-tripping of items not controlled by any field.

to_python(nbt: nbtparse.syntax.tags.CompoundTag) → {<class 'str'>: <class 'object'>}[source]
class nbtparse.semantics.fields.HomogenousDictField(nbt_name: str, *, default: {<class 'str'>: <class 'object'>}=None)[source]

Bases: nbtparse.semantics.fields.MutableField, nbtparse.semantics.fields.SingleField

Field for a dictionary of homogenous values.

Abstract. Subclasses should override item_to_python() and item_from_python().

from_python(mapping: {<class 'str'>: <class 'object'>}) → nbtparse.syntax.tags.CompoundTag[source]
item_from_python(key: str, value: object) -> (<class 'nbtparse.syntax.tags.StringTag'>, <class 'nbtparse.syntax.tags.AbstractTag'>)[source]
item_to_python(key: nbtparse.syntax.tags.StringTag, value: nbtparse.syntax.tags.AbstractTag) -> (<class 'str'>, <class 'object'>)[source]
to_python(nbt: nbtparse.syntax.tags.CompoundTag) → {<class 'str'>: <class 'object'>}[source]
class nbtparse.semantics.fields.IntArrayField(nbt_name: str, *, default: list=())[source]

Bases: nbtparse.semantics.fields.MutableField, nbtparse.semantics.fields.SingleField

Field for a TAG_Int_Array.

static from_python(value: list) → nbtparse.syntax.tags.IntArrayTag[source]
static to_python(tag: nbtparse.syntax.tags.IntArrayTag) → list[source]
class nbtparse.semantics.fields.IntField(nbt_name: str, *, default: int=0)[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_Int.

static from_python(value: int) → nbtparse.syntax.tags.IntTag[source]
static to_python(tag: nbtparse.syntax.tags.IntTag) → int[source]
class nbtparse.semantics.fields.ListField(nbt_name: str, item_to_python: function, item_from_python: function, content_id: int, *, default: list=())[source]

Bases: nbtparse.semantics.fields.MutableField, nbtparse.semantics.fields.SingleField

Field for a TAG_List.

The ListTag will be given an id of content_id for the elements.

from_python(l: list) → nbtparse.syntax.tags.ListTag[source]
to_python(l: nbtparse.syntax.tags.ListTag) → list[source]
class nbtparse.semantics.fields.LongField(nbt_name: str, *, default: int=0)[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_Long.

static from_python(value: int) → nbtparse.syntax.tags.LongTag[source]
static to_python(tag: nbtparse.syntax.tags.LongTag) → int[source]
class nbtparse.semantics.fields.MultiField(nbt_names: (<class 'str'>, Ellipsis), *, default: object=None)[source]

Bases: nbtparse.semantics.fields.AbstractField

Field combining multiple top-level tags into one object.

Controls a series of one or more top-level tags which should be combined into a single Pythonic object. If the tags are enclosed in a TAG_Compound, consider using an NBTObjectField instead.

This is an abstract class. to_python() will be called with the same number of arguments as nbt_names has elements, in the same order specified, and should return a value acceptable to from_python(), which should produce a sequence of the same values passed as arguments to to_python().

If a tag does not exist, to_python() will be passed None instead of the corresponding tag. If from_python() produces a None value, the corresponding tag will be removed.

default should be a value acceptable to from_python(), which will be called when setting the field to its default value.

Note

In general, these methods should not have side effects, and should not assume they are called at any particular time. The results may be cached and this class may assume that composing the two conversion methods produces the identity function. The reliable and comfortable hook for “heavy” NBT manipulation is save() and load().

delete_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]
from_python(value: object) -> (<class 'nbtparse.syntax.tags.AbstractTag'>, Ellipsis)[source]

Transform a single Pythonic object into several tags.

get_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str=None) → object[source]
set_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str, value: object)[source]
to_python(*tags: (<class 'nbtparse.syntax.tags.AbstractTag'>, Ellipsis)) → object[source]

Transform several tags into a single Pythonic object.

class nbtparse.semantics.fields.MutableField(*args, default=None, **kwargs)[source]

Bases: nbtparse.semantics.fields.AbstractField

Mutable variant of a field.

Caches the Pythonic value and holds a reference to it. Such a value can be safely mutated in-place. Needed for mutable types like lists, as well as immutable types whose contents may be mutable, such as tuples.

The value is cached in obj.__dict__[field_name].

This class must precede any class which overrides __get__(), __set__(), and/or __delete__() in the method resolution order. In particular, it must precede MultiField or SingleField. If you do not understand what that means, just make sure your code looks like this:

class FooField(MutableField, SingleField):
    pass

...rather than like this:

class FooField(SingleField, MutableField):
    pass
delete_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]
get_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str) → object[source]
load(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]
save(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]
set_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str, value: object)[source]
class nbtparse.semantics.fields.NBTObjectField(nbt_name: str, obj_class: 'nbtparse.semantics.nbtobject.NBTMeta', *, default: 'nbtparse.semantics.nbtobject.NBTObject'=None)[source]

Bases: nbtparse.semantics.fields.MutableField, nbtparse.semantics.fields.SingleField

Field for an NBTObject.

Usually a TAG_Compound but exact contents will vary.

attach(owner: 'nbtparse.semantics.nbtobject.NBTMeta')[source]
static from_python(obj: 'nbtparse.semantics.nbtobject.NBTObject') → nbtparse.syntax.tags.AbstractTag[source]
to_python(nbt: nbtparse.syntax.tags.AbstractTag) → 'nbtparse.semantics.nbtobject.NBTObject'[source]
class nbtparse.semantics.fields.ObjectListField(nbt_name: str, obj_class: 'nbtparse.semantics.nbtobject.NBTMeta', *, default: list=())[source]

Bases: nbtparse.semantics.fields.ListField

Field for a TAG_List of NBTObjects.

class nbtparse.semantics.fields.ObjectTupleField(nbt_name: str, obj_class: 'nbtparse.semantics.nbtobject.NBTMeta', *, default: ('nbtparse.semantics.nbtobject.NBTObject', Ellipsis)=())[source]

Bases: nbtparse.semantics.fields.TupleListField

Field for a TAG_List of NBTObjects, as a tuple.

class nbtparse.semantics.fields.ShortField(nbt_name: str, *, default: int=0)[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_Short.

static from_python(value: int) → nbtparse.syntax.tags.ShortTag[source]
static to_python(tag: nbtparse.syntax.tags.ShortTag) → int[source]
class nbtparse.semantics.fields.SingleField(nbt_name: str, *, typename: str=None, default: object=None)[source]

Bases: nbtparse.semantics.fields.AbstractField

Field for a single top-level tag.

This is an abstract class. to_python() is passed an NBT tag (see nbtparse.syntax.tags) and should return some object. That object should be acceptable to from_python(), which should return the equivalent NBT tag.

Concrete implementations must override either to_python() or to_python_ex(), and similarly either from_python() or from_python_ex().

Note

In general, these methods should not have side effects, and should not assume they are called at any particular time. The results may be cached and this class may assume that composing the two conversion methods produces the identity function. The reliable and comfortable hook for “heavy” NBT manipulation is save() and load().

delete_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]
from_python(value: object) → nbtparse.syntax.tags.AbstractTag[source]

Transform a Pythonic object into this tag.

from_python_ex(value: object, obj: 'nbtparse.semantics.nbtobject.NBTObject') → nbtparse.syntax.tags.AbstractTag[source]

Extended form of from_python().

Takes precedence if both are defined.

get_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str=None) → object[source]
set_field_value(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str, value: object)[source]
to_python(tag: nbtparse.syntax.tags.AbstractTag) → object[source]

Transform this tag into a Pythonic object.

to_python_ex(tag: nbtparse.syntax.tags.AbstractTag, obj: 'nbtparse.semantics.nbtobject.NBTObject') → object[source]

Extended form of to_python().

Takes precedence if both are defined.

class nbtparse.semantics.fields.TupleListField(nbt_name: str, item_to_python: function, item_from_python: function, content_id: int, *, default: (<class 'object'>, Ellipsis)=())[source]

Bases: nbtparse.semantics.fields.MutableField, nbtparse.semantics.fields.SingleField

Field for a TAG_List; converts to a tuple.

This should not be confused with TupleMultiField, which takes several top-level tags and wraps them together into a single field. This takes a single TAG_List and converts it into a tuple. ListField takes a single TAG_List and converts it into a list.

from_python(l: tuple) → nbtparse.syntax.tags.ListTag[source]
to_python(l: nbtparse.syntax.tags.ListTag) → tuple[source]
class nbtparse.semantics.fields.TupleMultiField(nbt_names: (<class 'str'>, Ellipsis), to_pythons: (<class 'function'>, Ellipsis), from_pythons: (<class 'function'>, Ellipsis), *, default: (<class 'object'>, Ellipsis)=None)[source]

Bases: nbtparse.semantics.fields.MutableField, nbtparse.semantics.fields.MultiField

Field which combines several tags into a tuple.

to_pythons and from_pythons should be sequences of functions which translate each item listed in nbt_names into its corresponding Python value.

from_python(values: (<class 'object'>, Ellipsis)) -> (<class 'nbtparse.syntax.tags.AbstractTag'>, Ellipsis)[source]
to_python(*raws: (<class 'nbtparse.syntax.tags.AbstractTag'>, Ellipsis)) -> (<class 'object'>, Ellipsis)[source]
class nbtparse.semantics.fields.UTCField(nbt_name: str, *, default: datetime.datetime=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc))[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_Long holding a Unix timestamp.

A default of NOW indicates the field should default to the current time.

Note

The datetime objects produced by this field are always aware, with a tzinfo value of utc. The field does accept naive objects, but it assumes they represent local time, which may not be correct for your application. In particular, the convention of using naive objects to represent UTC is not supported and will produce incorrect results unless local time is UTC.

static from_python(dt: datetime.datetime) → nbtparse.syntax.tags.LongTag[source]
set_default(obj: 'nbtparse.semantics.nbtobject.NBTObject', field_name: str)[source]
static to_python(nbt: nbtparse.syntax.tags.LongTag) → datetime.datetime[source]
class nbtparse.semantics.fields.UUIDField(high_name: str, low_name: str, *, default: uuid.UUID=None)[source]

Bases: nbtparse.semantics.fields.MultiField

Field which combines two TAG_Long‘s into a UUID.

A default of NEW_UUID will generate a new UUID every time. Assigning None in the ordinary fashion is equivalent to deleting the field.

static from_python(uuid_instance: uuid.UUID) -> (<class 'nbtparse.syntax.tags.LongTag'>, <class 'nbtparse.syntax.tags.LongTag'>)[source]
set_default(obj: object, field_name: str)[source]

If this field’s default is None, generate a UUID.

static to_python(high_tag: nbtparse.syntax.tags.LongTag, low_tag: nbtparse.syntax.tags.LongTag) → uuid.UUID[source]
class nbtparse.semantics.fields.UnicodeField(nbt_name: str, *, default: str='')[source]

Bases: nbtparse.semantics.fields.SingleField

Field for a TAG_String.

static from_python(value: str) → nbtparse.syntax.tags.StringTag[source]
static to_python(tag: nbtparse.syntax.tags.StringTag) → str[source]

Sentinel values

Some of the field classes can accept sentinel values as defaults or in other places.

Note

These sentinel values are only usable in the specific contexts they support (for example, as default values). They are not interpreted by __set__() or in any other contexts. In other words, this is illegal:

>>> foo.timestamp = NOW  # Use datetime.now(timezone.utc)
>>> foo.uuid = NEW_UUID  # Use uuid.uuid4()

But you can do this:

class Foo(NBTObject):
    timestamp = UTCField('timestamp', default=NOW)
    uuid = UUIDField('uuid1', 'uuid2', default=NEW_UUID)
nbtparse.semantics.fields.SELF_REFERENCE

Sentinel value for NBTObjectField.

When passed as the obj_class argument, refers to the class in which the field is declared. If the field is not declared inside a subclass of NBTObject, undefined behavior occurs.

nbtparse.semantics.fields.NOW

Sentinel value for UTCField.

Indicates the field should default to the current time.

nbtparse.semantics.fields.NEW_UUID

Sentinel value for UUIDField.

When used as the default value, indicates that the field should create a new type 4 UUID for each instantiation.

filetype Module

Provides classes for working with NBT files as objects.

These classes extend nbtparse.semantics.nbtobject and provide save and load methods so the file can be easily (de)serialized.

class nbtparse.semantics.filetype.GzippedNBTFile(*args, **kwargs)[source]

Bases: nbtparse.semantics.filetype.NBTFile

Gzipped variant of NBTFile.

classmethod load(input: io.BufferedIOBase)[source]

Creates a new NBTFile from the gzipped input file-like.

save(output: io.BufferedIOBase, rootname: str='')[source]

Writes this file to output as gzipped NBT.

class nbtparse.semantics.filetype.NBTFile(*args, **kwargs)[source]

Bases: nbtparse.semantics.nbtobject.NBTObject

Simple class for handling NBT encoded files holistically.

An entire NBT file is read and decoded via tags.decode_named, and then converted into a Pythonic object.

classmethod load(input: io.BufferedIOBase)[source]

Creates a new NBTFile from the input file-like.

Returns (rootname, NBTFile), where rootname is the name of the root tag. Conventional NBTObjects do not make use of their external names, so if you intend to use it somewhere, you need to capture it here.

save(output: io.BufferedIOBase, rootname: str='')[source]

Writes this file to output as NBT.

The root tag will be called rootname.

nbtobject Module

NBT high-level object-oriented class

NBTObject is an object-oriented wrapper for CompoundTag, designed to expose its fields in a standard and well-documented fashion.

class nbtparse.semantics.nbtobject.NBTMeta[source]

Bases: type

Metaclass for NBTObjects.

Allows NBTObjects to track their fields upon creation.

all_fields() → collections.abc.Set[source]

Return a set of all fields attached to this class.

Includes fields whose names begin with underscores.

Note

Fields defined in classes which do not derive from NBTObject will not be included. This is of no concern to most developers, but may cause problems if you plan on using multiple inheritance to provide the same fields to several different classes. To avoid this issue, always derive your mixin classes from NBTObject.

fields() → collections.abc.Set[source]

Return a set of the public fields attached to this class.

The elements of the set are strings whose names correspond to those of the fields. They are suitable arguments for getattr() and setattr().

Does not include fields whose names begin with underscores, but is otherwise equivalent to all_fields().

class nbtparse.semantics.nbtobject.NBTObject(*args, **kwargs)[source]

Bases: object

Thin wrapper over a TAG_Compound.

Typically houses one or more fields.

Calling the constructor directly will create an empty object with all fields set to their default values, except for any specifically initialized as keyword arguments. Calling from_nbt() will populate fields from the provided NBT.

Note

If the default of a field is None, that field will be set to None, which is equivalent to leaving it empty. Such fields will not be present in the generated NBT unless their values are changed by hand. In some cases, this means newly created objects will require modification before they can be meaningfully saved.

classmethod all_fields() → collections.abc.Set[source]

Forwards to NBTMeta.all_fields(), which see.

data = None

The underlying CompoundTag for this NBTObject.

Fields store and retrieve instance data in this attribute. It is largely used as-is when calling to_nbt(), but some fields may customize this process in their save() methods. Some NBTObjects will also alter the output by overriding to_nbt(). For these reasons, direct manipulation of this attribute is discouraged. It may still prove useful for debugging or for cases where a key is not controlled by any field.

classmethod fields() → collections.abc.Set[source]

Forwards to NBTMeta.fields(), which see.

classmethod from_bytes(raw: bytes)[source]

Deserialize a new NBTObject from a bytes object.

The name of the root tag is discarded.

classmethod from_nbt(nbt: nbtparse.syntax.tags.CompoundTag)[source]

Creates a new NBTObject from the given NBT representation.

Stores the given NBT in the data attribute of the newly-created object.

Also calls the load() methods of all the fields.

classmethod prepare_load(nbt: nbtparse.syntax.tags.CompoundTag) → nbtparse.syntax.tags.CompoundTag[source]

Hook called during from_nbt() with the loaded NBT.

Should return a CompoundTag after (for instance) unwrapping data inside a singleton CompoundTag or performing other transformations.

Unless overridden, return argument unchanged.

This hook runs before any fields’ load() methods are called. It is the first hook after the NBT has been loaded.

Note

Unlike prepare_save(), this method must be callable as a class method. In practice, both methods can often be implemented as static methods anyway.

prepare_save(nbt: nbtparse.syntax.tags.CompoundTag) → nbtparse.syntax.tags.CompoundTag[source]

Hook called during to_nbt() with the to-be-saved NBT.

Should return a CompoundTag after (for instance) wrapping data inside a singleton CompoundTag or performing other transformations.

Unless overridden, return argument unchanged.

This hook runs after all fields’ save() methods are called. It is the last hook before the NBT is saved.

to_bytes() → bytes[source]

Serialize this NBTObject directly to a bytes object.

The root tag will have no name.

to_nbt() → nbtparse.syntax.tags.CompoundTag[source]

Returns an NBT representation of this object.

By default, return self.data, which is sufficient if all data is kept in fields.

Also calls the save() methods of all the fields.