VDF Python Library
The `vdf` library is a pure Python module for serialization and deserialization of Valve's KeyValue (VDF) text and binary formats. It provides an interface similar to Python's built-in `json` module. The current version is 3.4, and it is actively maintained with an irregular release cadence, supporting KV1 format while KV2 and KV3 are not supported.
Common errors
-
ModuleNotFoundError: No module named 'vdf'
cause The `vdf` package is either not installed in the active Python environment, or there's a conflict with multiple Python installations (e.g., system Python vs. `pyenv`/`conda`) where the package is installed for a different interpreter. This can also happen if a wrapper script (like `protontricks`) expects `vdf` in a specific Python version's `site-packages` that doesn't match the installed version.fixEnsure `vdf` is installed for your active Python interpreter using `pip install vdf`. If using virtual environments, activate the correct environment first. If using tools like `protontricks`, verify that the Python environment it targets has `vdf` installed, potentially by forcing installation for a specific Python version or ensuring path consistency. -
TypeError: 'VDFDict' object is not subscriptable
cause This error can occur if you're trying to access a nested key directly on the top-level `VDFDict` object that doesn't exist at that level, or if you're attempting to treat a single value as a dictionary/list. It might also happen if a key that you expect to be a sub-dictionary is actually a single value due to parsing.fixInspect the structure of your VDF data after deserialization. Remember that `VDFDict` works like `dict`, and nested values are accessed sequentially (e.g., `data_vdfdict['Config']['Key1']`). If duplicate keys exist, `VDFDict` stores them as a list of values, so you might need to iterate or access by index (e.g., `data_vdfdict['Config']['Key1'][0]`) if you're expecting a single string.
Warnings
- gotcha The VDF format allows duplicate keys within an object, but standard Python `dict`s do not (prior to Python 3.7 where insertion order is preserved, and later versions that handle duplicates differently). When deserializing VDF with duplicate keys, `vdf.loads()` or `vdf.load()` will, by default, overwrite earlier values for the same key.
- gotcha Python `dict`s in versions prior to 3.6 do not guarantee insertion order. If key order is crucial for your application when working with older Python environments, direct deserialization to a `dict` might lead to unexpected results.
- gotcha Comments present in a VDF file are not preserved during the deserialization process. If you parse a VDF file that contains comments and then serialize it back, the comments will be lost.
Install
-
pip install vdf
Imports
- vdf
import vdf
- VDFDict
import vdf.VDFDict
from vdf import VDFDict
Quickstart
import vdf
from collections import OrderedDict
vdf_text = '"Config" { "Key1" "Value1" "Key2" "Value2" "Key1" "AnotherValue" }'
# Deserialize VDF text to a Python dictionary (loses duplicate keys prior to Python 3.7)
data_dict = vdf.loads(vdf_text)
print(f"Standard dict (may lose duplicates): {data_dict}")
# Deserialize VDF text preserving order and handling duplicates with VDFDict
data_vdfdict = vdf.loads(vdf_text, mapper=vdf.VDFDict)
print(f"VDFDict (preserves order and duplicates): {data_vdfdict}")
print(f"Accessing a duplicated key in VDFDict: {data_vdfdict['Config']['Key1']}") # Returns a list
# Serialize a Python dictionary to VDF text
output_dict = {'Game': {'Name': 'MyGame', 'Version': '1.0'}}
vdf_output = vdf.dumps(output_dict, pretty=True)
print(f"\nSerialized VDF:\n{vdf_output}")
# Example of binary VDF (requires bytes input/output)
# For demonstration, we'll simulate binary data.
binary_vdf_bytes = b'\x00Config\x00\x00Key1\x00Value1\x00\x00Key2\x00Value2\x00\x08'
binary_data = vdf.binary_loads(binary_vdf_bytes)
print(f"\nDeserialized binary VDF: {binary_data}")
# Example of VBKV (ValueBinaryKeyValue) with header and CRC checking
# This often requires specific bytes patterns for actual Valve files.
# For a real scenario, vbkv_bytes would come from a file.
# Here, we'll just demonstrate the call.
# try:
# vbkv_data = vdf.vbkv_loads(b'some_vbkv_bytes_with_header_and_crc')
# print(f"Deserialized VBKV: {vbkv_data}")
# except Exception as e:
# print(f"VBKV deserialization error (expected if bytes are not valid): {e}")