{"id":8758,"library":"vdf","title":"VDF Python Library","description":"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.","status":"active","version":"3.4","language":"en","source_language":"en","source_url":"https://github.com/ValvePython/vdf","tags":["valve","keyvalue","vdf","serialization","deserialization","config","parser"],"install":[{"cmd":"pip install vdf","lang":"bash","label":"Install latest stable version"}],"dependencies":[],"imports":[{"symbol":"vdf","correct":"import vdf"},{"note":"`VDFDict` is a class within the `vdf` module, commonly imported directly for clarity when used as a custom mapper.","wrong":"import vdf.VDFDict","symbol":"VDFDict","correct":"from vdf import VDFDict"}],"quickstart":{"code":"import vdf\nfrom collections import OrderedDict\n\nvdf_text = '\"Config\" { \"Key1\" \"Value1\" \"Key2\" \"Value2\" \"Key1\" \"AnotherValue\" }'\n\n# Deserialize VDF text to a Python dictionary (loses duplicate keys prior to Python 3.7)\ndata_dict = vdf.loads(vdf_text)\nprint(f\"Standard dict (may lose duplicates): {data_dict}\")\n\n# Deserialize VDF text preserving order and handling duplicates with VDFDict\ndata_vdfdict = vdf.loads(vdf_text, mapper=vdf.VDFDict)\nprint(f\"VDFDict (preserves order and duplicates): {data_vdfdict}\")\nprint(f\"Accessing a duplicated key in VDFDict: {data_vdfdict['Config']['Key1']}\") # Returns a list\n\n# Serialize a Python dictionary to VDF text\noutput_dict = {'Game': {'Name': 'MyGame', 'Version': '1.0'}}\nvdf_output = vdf.dumps(output_dict, pretty=True)\nprint(f\"\\nSerialized VDF:\\n{vdf_output}\")\n\n# Example of binary VDF (requires bytes input/output)\n# For demonstration, we'll simulate binary data.\nbinary_vdf_bytes = b'\\x00Config\\x00\\x00Key1\\x00Value1\\x00\\x00Key2\\x00Value2\\x00\\x08'\nbinary_data = vdf.binary_loads(binary_vdf_bytes)\nprint(f\"\\nDeserialized binary VDF: {binary_data}\")\n\n# Example of VBKV (ValueBinaryKeyValue) with header and CRC checking\n# This often requires specific bytes patterns for actual Valve files.\n# For a real scenario, vbkv_bytes would come from a file.\n# Here, we'll just demonstrate the call.\n# try:\n#     vbkv_data = vdf.vbkv_loads(b'some_vbkv_bytes_with_header_and_crc')\n#     print(f\"Deserialized VBKV: {vbkv_data}\")\n# except Exception as e:\n#     print(f\"VBKV deserialization error (expected if bytes are not valid): {e}\")","lang":"python","description":"This quickstart demonstrates how to parse and dump VDF data, including handling text and binary formats. It highlights the use of `vdf.VDFDict` for correctly managing duplicate keys and preserving order, which are common challenges with the VDF format."},"warnings":[{"fix":"Use `vdf.loads(vdf_string, mapper=vdf.VDFDict)` or `vdf.loads(vdf_string, mapper=collections.OrderedDict)` to preserve all duplicate keys as a list of values, or to maintain insertion order, respectively. `vdf.VDFDict` is specifically designed to handle VDF's duplicate key behavior.","message":"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.","severity":"gotcha","affected_versions":"<3.0"},{"fix":"Always use `collections.OrderedDict` or `vdf.VDFDict` as the `mapper` when loading VDF data if key order is important, especially on Python versions older than 3.6. For example: `vdf.loads(vdf_text, mapper=collections.OrderedDict)`.","message":"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.","severity":"gotcha","affected_versions":"<3.6"},{"fix":"This is a fundamental behavior of the library; if comment preservation is critical, `vdf` might not be the suitable tool, or comments would need to be handled by a separate parsing layer before passing data to `vdf`.","message":"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.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure `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.","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.","error":"ModuleNotFoundError: No module named 'vdf'"},{"fix":"Inspect 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.","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.","error":"TypeError: 'VDFDict' object is not subscriptable"}]}