{"id":13817167,"url":"https://github.com/vberlier/nbtlib","last_synced_at":"2025-04-06T19:11:24.442Z","repository":{"id":25350371,"uuid":"103789098","full_name":"vberlier/nbtlib","owner":"vberlier","description":"A python library to read and edit nbt data.","archived":false,"fork":false,"pushed_at":"2022-12-19T01:06:56.000Z","size":7077,"stargazers_count":131,"open_issues_count":21,"forks_count":17,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-30T18:08:25.024Z","etag":null,"topics":["minecraft","nbt","nbt-parser","nbtlib","schema"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vberlier.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["vberlier"]}},"created_at":"2017-09-16T22:58:40.000Z","updated_at":"2025-03-13T14:34:42.000Z","dependencies_parsed_at":"2023-01-14T02:35:27.819Z","dependency_job_id":null,"html_url":"https://github.com/vberlier/nbtlib","commit_stats":null,"previous_names":[],"tags_count":66,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vberlier%2Fnbtlib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vberlier%2Fnbtlib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vberlier%2Fnbtlib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vberlier%2Fnbtlib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vberlier","download_url":"https://codeload.github.com/vberlier/nbtlib/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247535517,"owners_count":20954576,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["minecraft","nbt","nbt-parser","nbtlib","schema"],"created_at":"2024-08-04T06:00:35.714Z","updated_at":"2025-04-06T19:11:24.413Z","avatar_url":"https://github.com/vberlier.png","language":"Python","funding_links":["https://github.com/sponsors/vberlier"],"categories":["Misc"],"sub_categories":[],"readme":"# nbtlib\r\n\r\n[![GitHub Actions](https://github.com/vberlier/nbtlib/workflows/CI/badge.svg)](https://github.com/vberlier/nbtlib/actions)\r\n[![PyPI](https://img.shields.io/pypi/v/nbtlib.svg)](https://pypi.org/project/nbtlib/)\r\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nbtlib.svg)](https://pypi.org/project/nbtlib/)\r\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\r\n[![Discord](https://img.shields.io/discord/900530660677156924?color=7289DA\u0026label=discord\u0026logo=discord\u0026logoColor=fff)](https://discord.gg/98MdSGMm8j)\r\n\r\n\u003e A python library to read and edit [nbt data](http://wiki.vg/NBT). Requires\r\n\u003e python 3.8.\r\n\r\n**Features**\r\n\r\n- Create, read and edit nbt files\r\n- Supports gzipped and uncompressed files\r\n- Supports big-endian and little-endian files\r\n- Parse and serialize raw nbt data\r\n- Define tag schemas that automatically enforce predefined tag types\r\n- Convert nbt between binary form and literal notation\r\n- Use nbt paths to access deeply nested properties\r\n- Includes a CLI to quickly perform read/write/merge operations\r\n\r\n## Installation\r\n\r\n\u003e **Notice 🚧**\r\n\u003e\r\n\u003e Version `2.0` is actively being worked on and is not stable yet. You should probably keep using version `1.12.1` for the moment. You can check out the `2.0` roadmap in the [`nbtlib 2.0` issue](https://github.com/vberlier/nbtlib/issues/156).\r\n\r\nThe package can be installed with `pip`.\r\n\r\n```bash\r\n$ pip install \"nbtlib==1.12.1\"\r\n```\r\n\r\n## Basic usage\r\n\r\nThe following examples will give you a very basic overview of what you\r\ncan do. For more advanced examples, check out the\r\n\"[Usage](https://github.com/vberlier/nbtlib/blob/main/docs/Usage.ipynb)\"\r\nnotebook in the docs folder.\r\n\r\n### Reading files\r\n\r\nThe `nbtlib.load` function can be used to load nbt files as `nbtlib.File` objects. Every nbt tag inherits from\r\nits python counterpart. This means that all the builtin operations defined on the python counterpart can be used on nbt tags.\r\n\r\n```python\r\nimport nbtlib\r\n\r\nnbt_file = nbtlib.load('bigtest.nbt')\r\nassert nbt_file['intTest'] == 2147483647\r\n```\r\n\r\nFor example, instances of `nbtlib.File` inherit from regular `Compound` tags, which themselves inherit from the builtin python dictionary `dict`. Similarly, instances of `Int` tags inherit from the builtin class `int`.\r\n\r\nFor more details on loading nbt files and how to work with nbt tags check out the \"[Usage](https://github.com/vberlier/nbtlib/blob/main/docs/Usage.ipynb)\"\r\nnotebook.\r\n\r\n### Editing files\r\n\r\nYou can use instances of `nbtlib.File` as context managers in order to save modifications\r\nautomatically at the end of the `with` statement.\r\n\r\n```python\r\nimport nbtlib\r\nfrom nbtlib.tag import Int\r\n\r\nwith nbtlib.load('demo.nbt') as demo:\r\n    demo['counter'] = Int(demo['counter'] + 1)\r\n```\r\n\r\nYou can also call the `save` method manually.\r\n\r\n```python\r\nimport nbtlib\r\nfrom nbtlib.tag import Int\r\n\r\ndemo = nbtlib.load('demo.nbt')\r\ndemo['counter'] = Int(demo['counter'] + 1)\r\ndemo.save()\r\n```\r\n\r\nFor more details on the `save` method check out the \"[Usage](https://github.com/vberlier/nbtlib/blob/main/docs/Usage.ipynb)\"\r\nnotebook.\r\n\r\n### Using schemas\r\n\r\n`nbtlib` allows you to define `Compound` schemas that enforce a specific tag type\r\nfor any given key.\r\n\r\n```python\r\nfrom nbtlib import schema\r\nfrom nbtlib.tag import Short, String\r\n\r\nMySchema = schema('MySchema', {\r\n    'foo': String,\r\n    'bar': Short\r\n})\r\n\r\nmy_object = MySchema({'foo': 'hello world', 'bar': 21})\r\n\r\nassert isinstance(my_object, MySchema)\r\nassert isinstance(my_object['foo'], String)\r\n```\r\n\r\nFor more details on schemas check out the \"[Usage](https://github.com/vberlier/nbtlib/blob/main/docs/Usage.ipynb)\"\r\nnotebook.\r\n\r\n### Nbt literals\r\n\r\nYou can parse nbt literals using the `nbtlib.parse_nbt` function.\r\n\r\n```python\r\nfrom nbtlib import parse_nbt\r\nfrom nbtlib.tag import String, List, Compound, IntArray\r\n\r\nmy_compound = parse_nbt('{foo: [hello, world], bar: [I; 1, 2, 3]}')\r\nassert my_compound == Compound({\r\n    'foo': List[String](['hello', 'world']),\r\n    'bar': IntArray([1, 2, 3])\r\n})\r\n```\r\n\r\nNbt tags can be serialized to their literal representation with the `nbtlib.serialize_tag` function.\r\n\r\n```python\r\nfrom nbtlib import serialize_tag\r\nfrom nbtlib.tag import String, List, Compound, IntArray\r\n\r\nmy_compound = Compound({\r\n    'foo': List[String](['hello', 'world']),\r\n    'bar': IntArray([1, 2, 3])\r\n})\r\nassert serialize_tag(my_compound) == '{foo: [\"hello\", \"world\"], bar: [I; 1, 2, 3]}'\r\n```\r\n\r\nFor more details on nbt literals check out the \"[Usage](https://github.com/vberlier/nbtlib/blob/main/docs/Usage.ipynb)\"\r\nnotebook.\r\n\r\n### Nbt paths\r\n\r\nNbt paths can be used to access deeply nested properties in nbt data. The implementation is based on information available on the [Minecraft wiki](https://minecraft.gamepedia.com/Commands/data#NBT_path).\r\n\r\n```python\r\nfrom nbtlib import parse_nbt, Path\r\n\r\ndata = parse_nbt('{a: [{b: {c: 42}}]}')\r\nassert data['a'][0]['b']['c'] == 42\r\nassert data[Path('a[0].b.c')] == 42\r\n```\r\n\r\nYou can retrieve, modify and delete multiple properties at the same time.\r\n\r\n```python\r\nfrom nbtlib import parse_nbt, Path\r\nfrom nbtlib.tag import Int\r\n\r\ndata = parse_nbt('{foo: [{a: 1, b: {c: 42}}, {a: 2, b: {c: 0}}]}')\r\n\r\ndata[Path('foo[].a')] = Int(99)\r\nassert str(data) == '{foo: [{a: 99, b: {c: 42}}, {a: 99, b: {c: 0}}]}'\r\n\r\nassert data.get_all(Path('foo[].b.c')) == [42, 0]\r\n\r\ndel data[Path('foo[].b{c: 0}')]\r\nassert str(data) == '{foo: [{a: 99, b: {c: 42}}, {a: 99}]}'\r\n```\r\n\r\nNbt paths are immutable but can be manipulated and combined together to form new paths.\r\n\r\n```python\r\nfrom nbtlib import Path\r\nfrom nbtlib.tag import Compound\r\n\r\npath = Path()['hello']['world']\r\nassert path[:][Compound({'a': Int(0)})] == 'hello.world[{a: 0}]'\r\n\r\nassert path + path == 'hello.world.hello.world'\r\nassert sum('abcdef', Path()) == 'a.b.c.d.e.f'\r\n\r\nassert Path()[0] + 'foo{a: 1}' + '{b: 2}.bar' == '[0].foo{a: 1, b: 2}.bar'\r\n\r\nassert path['key.with.dots'] == 'hello.world.\"key.with.dots\"'\r\nassert path + 'key.with.dots' == 'hello.world.key.with.dots'\r\n\r\n```\r\n\r\n## Command-line interface\r\n\r\nThe package comes with a small CLI that makes it easy to quickly perform\r\nbasic operations on nbt files.\r\n\r\n```\r\n$ nbt --help\r\nusage: nbt [-h] [-r | -s] [-w \u003cnbt\u003e | -m \u003cnbt\u003e] [--plain] [--little]\r\n           [--compact] [--pretty] [--unpack] [--json]\r\n           [--path \u003cpath\u003e] [--find \u003cpath\u003e]\r\n           \u003cfile\u003e\r\n\r\nPerform operations on nbt files.\r\n\r\npositional arguments:\r\n  \u003cfile\u003e         the target file\r\n\r\noptional arguments:\r\n  -h, --help     show this help message and exit\r\n  -r             read nbt data from a file\r\n  -s             read snbt from a file\r\n  -w \u003cnbt\u003e       write nbt to a file\r\n  -m \u003cnbt\u003e       merge nbt into a file\r\n  --plain        don't use gzip compression\r\n  --little       use little-endian format\r\n  --compact      output compact snbt\r\n  --pretty       output indented snbt\r\n  --unpack       output interpreted nbt\r\n  --json         output nbt as json\r\n  --path \u003cpath\u003e  output all the matching tags\r\n  --find \u003cpath\u003e  recursively find the first matching tag\r\n```\r\n\r\n### Read nbt data\r\n\r\nYou can read nbt files by using the `-r` option. This will print the\r\nliteral notation of the binary nbt data.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt\r\n{foo: [1, 2, 3], bar: \"Hello, world!\"}\r\n```\r\n\r\nYou can use the following command if you want to save the output into a\r\nfile.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt \u003e my_file.snbt\r\n```\r\n\r\nUsing the `--compact` argument will remove all the extra whitespace from the output.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt --compact\r\n{foo:[1,2,3],bar:\"Hello, world!\"}\r\n```\r\n\r\nYou can use the `--pretty` argument if you want the command to output indented snbt.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt --pretty\r\n{\r\n    foo: [1, 2, 3],\r\n    bar: \"Hello, world!\"\r\n}\r\n```\r\n\r\nThe output can be converted to json with the `--json` flag.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt --json\r\n{\"foo\": [1, 2, 3], \"bar\": \"Hello, world!\"}\r\n```\r\n\r\nThe `--path` option lets you output tags that match a given path.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt --path \"bar\"\r\n\"Hello, world!\"\r\n$ nbt -r my_file.nbt --path \"foo[]\"\r\n1\r\n2\r\n3\r\n```\r\n\r\nYou can combine this with the `--unpack` flag to print out the unpacked python objects.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt --path \"bar\" --unpack\r\nHello, world!\r\n```\r\n\r\nIf you don't know exactly how to access the data you're interested in you can use the `--find` option to recursively try to match a given path.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt --find \"[1]\"\r\n2\r\n```\r\n\r\nYou can also perform all these operations on snbt by using the `-s` option instead of the `-r` option.\r\n\r\n```bash\r\n$ nbt -s foo.snbt --path bar\r\n\"Hello, world!\"\r\n```\r\n\r\n### Write nbt data\r\n\r\nYou can write nbt data to a file by using the `-w` option. This will\r\nconvert the literal nbt notation to its binary form and save it in the\r\nspecified file.\r\n\r\n```bash\r\n$ nbt -w '{foo:[1,2,3],bar:{hello:[B;1b,1b,0b,1b]}}' my_file.nbt\r\n```\r\n\r\nThe file will be created if it doesn't already exist.\r\n\r\nYou can combine the `-w` flag with other flags to read, filter and write nbt data.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt --path \"bar\" -w bar.nbt\r\n```\r\n\r\n### Merge nbt data\r\n\r\nFinally, you can merge some nbt data into an already existing file by\r\nusing the `-m` option. This will recursively update the file with\r\nthe values parsed from the literal argument.\r\n\r\n```bash\r\n$ nbt -m '{bar:{\"new key\":56f}}' my_file.nbt\r\n```\r\n\r\nYou can check the result by using the `-r` option.\r\n\r\n```bash\r\n$ nbt -r my_file.nbt\r\n{foo: [1, 2, 3], bar: {hello: [B; 1B, 1B, 0B, 1B], \"new key\": 56.0f}}\r\n```\r\n\r\nHere, the compound values that aren't present in the input literal are\r\nleft untouched. Using the `-w` option instead of `-m` would\r\noverwrite the whole file.\r\n\r\nYou can combine the `-m` flag with other flags to read, filter and merge nbt data.\r\n\r\n```bash\r\n$ nbt -s foo.snbt -m my_file.nbt\r\n```\r\n\r\n### Compression and byte order\r\n\r\nBy default, the CLI will assume that you're working with gzipped nbt\r\nfiles. If you want to read, write or merge uncompressed nbt files, you\r\ncan use the `--plain` option. Similarly, the default byte order is\r\nbig-endian so you'll need to use the `--little` option to perform\r\noperations on little-endian files.\r\n\r\n**Reading**\r\n\r\n```bash\r\n$ nbt -r my_file.nbt --plain --little\r\n{name: \"Reading an uncompressed little-endian file\"}\r\n```\r\n\r\n**Writing**\r\n\r\n```bash\r\n$ nbt -w '{name:\"Writing in an uncompressed little-endian file\"}' my_file.nbt --plain --little\r\n```\r\n\r\n**Merging**\r\n\r\n```bash\r\n$ nbt -m '{name:\"Merging in an uncompressed little-endian file\"}' my_file.nbt --plain --little\r\n```\r\n\r\n## Contributing\r\n\r\nContributions are welcome. This project uses [`poetry`](https://poetry.eustace.io/) so you'll need to install it first if you want to be able to work with the project locally.\r\n\r\n```sh\r\n$ curl -sSL https://raw.githubusercontent.com/sdispater/poetry/main/get-poetry.py | python\r\n```\r\n\r\nYou should now be able to install the required dependencies.\r\n\r\n```sh\r\n$ poetry install\r\n```\r\n\r\nYou can run the tests with `poetry run pytest`.\r\n\r\n```sh\r\n$ poetry run pytest\r\n```\r\n\r\n---\r\n\r\nLicense - [MIT](https://github.com/vberlier/nbtlib/blob/main/LICENSE)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvberlier%2Fnbtlib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvberlier%2Fnbtlib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvberlier%2Fnbtlib/lists"}