1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
| |pypi| |license| |coverage| |master_build|
| |sonar_maintainability| |sonar_reliability| |sonar_security|
Pure python module for (de)serialization to and from VDF that works just like ``json``.
Tested and works on ``py2.7``, ``py3.3+``, ``pypy`` and ``pypy3``.
VDF is Valve's KeyValue text file format
https://developer.valvesoftware.com/wiki/KeyValues
| Supported versions: ``kv1``
| Unsupported: ``kv2`` and ``kv3``
Install
-------
You can grab the latest release from https://pypi.org/project/vdf/ or via ``pip``
.. code:: bash
pip install vdf
Install the current dev version from ``github``
.. code:: bash
pip install git+https://github.com/ValvePython/vdf
Problems & solutions
--------------------
- There are known files that contain duplicate keys. This is supported the format and
makes mapping to ``dict`` impossible. For this case the module provides ``vdf.VDFDict``
that can be used as mapper instead of ``dict``. See the example section for details.
- By default de-serialization will return a ``dict``, which doesn't preserve nor guarantee
key order on Python versions prior to 3.6, due to `hash randomization`_. If key order is
important on old Pythons, I suggest using ``collections.OrderedDict``, or ``vdf.VDFDict``.
Example usage
-------------
For text representation
.. code:: python
import vdf
# parsing vdf from file or string
d = vdf.load(open('file.txt'))
d = vdf.loads(vdf_text)
d = vdf.parse(open('file.txt'))
d = vdf.parse(vdf_text)
# dumping dict as vdf to string
vdf_text = vdf.dumps(d)
indented_vdf = vdf.dumps(d, pretty=True)
# dumping dict as vdf to file
vdf.dump(d, open('file2.txt','w'), pretty=True)
For binary representation
.. code:: python
d = vdf.binary_loads(vdf_bytes)
b = vdf.binary_dumps(d)
# alternative format - VBKV
d = vdf.binary_loads(vdf_bytes, alt_format=True)
b = vdf.binary_dumps(d, alt_format=True)
# VBKV with header and CRC checking
d = vdf.vbkv_loads(vbkv_bytes)
b = vdf.vbkv_dumps(d)
Using an alternative mapper
.. code:: python
d = vdf.loads(vdf_string, mapper=collections.OrderedDict)
d = vdf.loads(vdf_string, mapper=vdf.VDFDict)
``VDFDict`` works much like the regular ``dict``, except it handles duplicates and remembers
insert order. Additionally, keys can only be of type ``str``. The most important difference
is that when trying to assigning a key that already exist it will create a duplicate instead
of reassign the value to the existing key.
.. code:: python
>>> d = vdf.VDFDict()
>>> d['key'] = 111
>>> d['key'] = 222
>>> d
VDFDict([('key', 111), ('key', 222)])
>>> d.items()
[('key', 111), ('key', 222)]
>>> d['key']
111
>>> d[(0, 'key')] # get the first duplicate
111
>>> d[(1, 'key')] # get the second duplicate
222
>>> d.get_all_for('key')
[111, 222]
>>> d[(1, 'key')] = 123 # reassign specific duplicate
>>> d.get_all_for('key')
[111, 123]
>>> d['key'] = 333
>>> d.get_all_for('key')
[111, 123, 333]
>>> del d[(1, 'key')]
>>> d.get_all_for('key')
[111, 333]
>>> d[(1, 'key')]
333
>>> print vdf.dumps(d)
"key" "111"
"key" "333"
>>> d.has_duplicates()
True
>>> d.remove_all_for('key')
>>> len(d)
0
>>> d.has_duplicates()
False
.. |pypi| image:: https://img.shields.io/pypi/v/vdf.svg?style=flat&label=latest%20version
:target: https://pypi.org/project/vdf/
:alt: Latest version released on PyPi
.. |license| image:: https://img.shields.io/pypi/l/vdf.svg?style=flat&label=license
:target: https://pypi.org/project/vdf/
:alt: MIT License
.. |coverage| image:: https://img.shields.io/coveralls/ValvePython/vdf/master.svg?style=flat
:target: https://coveralls.io/r/ValvePython/vdf?branch=master
:alt: Test coverage
.. |sonar_maintainability| image:: https://sonarcloud.io/api/project_badges/measure?project=ValvePython_vdf&metric=sqale_rating
:target: https://sonarcloud.io/dashboard?id=ValvePython_vdf
:alt: SonarCloud Rating
.. |sonar_reliability| image:: https://sonarcloud.io/api/project_badges/measure?project=ValvePython_vdf&metric=reliability_rating
:target: https://sonarcloud.io/dashboard?id=ValvePython_vdf
:alt: SonarCloud Rating
.. |sonar_security| image:: https://sonarcloud.io/api/project_badges/measure?project=ValvePython_vdf&metric=security_rating
:target: https://sonarcloud.io/dashboard?id=ValvePython_vdf
:alt: SonarCloud Rating
.. |master_build| image:: https://github.com/ValvePython/vdf/workflows/Tests/badge.svg?branch=master
:target: https://github.com/ValvePython/vdf/actions?query=workflow%3A%22Tests%22+branch%3Amaster
:alt: Build status of master branch
.. _DuplicateOrderedDict: https://github.com/rossengeorgiev/dota2_notebooks/blob/master/DuplicateOrderedDict_for_VDF.ipynb
.. _hash randomization: https://docs.python.org/2/using/cmdline.html#envvar-PYTHONHASHSEED
|