From e32aafdfdd0472b19a5766b89d0a48123cab408f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Sat, 7 Sep 2019 15:27:27 +0300 Subject: [PATCH 01/29] Added support for unquoted keys starting with $ CSGO has material (.vmt) files that have unquoted keys starting with $. For example, csgo/materials/grass/hr_grass/grass_a.vmt: ``` LightmappedGeneric { $baseTexture "grass/hr_grass/grass_a" $bumpmap "grass/hr_grass/grass_a_normals" } ``` This fixes the parsing of these files. --- vdf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index 7bcd11c..90f0d11 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -86,7 +86,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): stack = [mapper()] expect_bracket = False - re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?]+))' + re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?\$?[a-z0-9\-\_\\\?]+))' r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' r'|(?P[a-z0-9\-\_\\\?\*\.]+)' From 000d024698d60b2bc575f38ca6bf6d03bbbd9296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Mon, 3 Feb 2020 22:30:18 +0200 Subject: [PATCH 02/29] Moved $ inside character set in unquoted key regex --- vdf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index 90f0d11..b45cef4 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -86,7 +86,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): stack = [mapper()] expect_bracket = False - re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?\$?[a-z0-9\-\_\\\?]+))' + re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$]+))' r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' r'|(?P[a-z0-9\-\_\\\?\*\.]+)' From 80958f5a603e4f74d6936e4638c3b172554fed91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Mon, 3 Feb 2020 22:33:17 +0200 Subject: [PATCH 03/29] Added support for % in unquoted keys --- vdf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index b45cef4..b8c585d 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -86,7 +86,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): stack = [mapper()] expect_bracket = False - re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$]+))' + re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$%]+))' r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' r'|(?P[a-z0-9\-\_\\\?\*\.]+)' From 6da1af90467aadc1d89c7a8c1d36a4a811df85fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Mon, 3 Feb 2020 22:54:48 +0200 Subject: [PATCH 04/29] Added support for single / inside unquoted values --- vdf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index b8c585d..a8ece43 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -89,7 +89,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$%]+))' r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' - r'|(?P[a-z0-9\-\_\\\?\*\.]+)' + r'|(?P(?:(? Date: Mon, 3 Feb 2020 22:57:19 +0200 Subject: [PATCH 05/29] Added support for $ in unquoted values --- vdf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index a8ece43..7dee67c 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -89,7 +89,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$%]+))' r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' - r'|(?P(?:(?(?:(? Date: Mon, 3 Feb 2020 23:17:24 +0200 Subject: [PATCH 06/29] Added support for empty blocks directly after keys --- vdf/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index 7dee67c..2c67f4f 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -90,6 +90,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' r'|(?P(?:(?{[ \t]*})' r'))?', flags=re.I) @@ -147,8 +148,10 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): _m = mapper() stack[-1][key] = _m - stack.append(_m) - expect_bracket = True + if match.group('eblock') is None: + # only expect a bracket if the block is not closed on the same line + stack.append(_m) + expect_bracket = True # we've matched a simple keyvalue pair, map it to the last dict obj in the stack else: From 6f645c7be408e6599fafc9a70322947e2546574b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Mon, 3 Feb 2020 23:21:41 +0200 Subject: [PATCH 07/29] Added support for in unquoted keys and values --- vdf/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index 2c67f4f..31aebe2 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -86,10 +86,10 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): stack = [mapper()] expect_bracket = False - re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$%]+))' + re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$%]+))' r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' - r'|(?P(?:(?(?:(?])+)' r'|(?P{[ \t]*})' r'))?', flags=re.I) From 74fb682f1a250607ce0969ee6a85e8afb770e180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Mon, 3 Feb 2020 23:41:53 +0200 Subject: [PATCH 08/29] Updated tests for new symbols & empty blocks --- tests/test_vdf.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/test_vdf.py b/tests/test_vdf.py index f041578..5163037 100644 --- a/tests/test_vdf.py +++ b/tests/test_vdf.py @@ -319,11 +319,12 @@ def test_hash_key(self): self.assertEqual(vdf.loads(INPUT, escaped=False), EXPECTED) def test_wierd_symbols_for_unquoted(self): - INPUT = 'a asd.vdf\nb language_*lol*\nc zxc_-*.sss//' + INPUT = 'a asd.vdf\nb language_*lol*\nc zxc_-*.sss//\nd<2?$% /cde/$fgh/' EXPECTED = { 'a': 'asd.vdf', 'b': 'language_*lol*', 'c': 'zxc_-*.sss', + 'd<2?$%': '/cde/$fgh/', } self.assertEqual(vdf.loads(INPUT), EXPECTED) @@ -393,6 +394,39 @@ def test_escape_before_last_unescaped(self): self.assertEqual(vdf.loads(INPUT, escaped=False), EXPECTED) + def test_single_line_empty_block(self): + INPUT = ''' + "root1" + { + "key1" {} + key2 "value2" + "key3" value3 + } + root2 { } + root3 + { + "key1" "value1" + key2 { } + "key3" value3 + } + ''' + + EXPECTED = { + 'root1': { + 'key1': {}, + 'key2': 'value2', + 'key3': 'value3', + }, + 'root2': {}, + 'root3': { + 'key1': 'value1', + 'key2': {}, + 'key3': 'value3', + } + } + + self.assertEqual(vdf.loads(INPUT), EXPECTED) + self.assertEqual(vdf.loads(INPUT, escaped=False), EXPECTED) class testcase_VDF_other(unittest.TestCase): def test_dumps_pretty_output(self): From ba557e58ca1c771936861eca42a95cfde358ba98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Sat, 2 May 2020 22:39:54 +0300 Subject: [PATCH 09/29] Fix parsing of inline opening brackets --- tests/test_vdf.py | 35 +++++++++++++++++++++++++++++++++++ vdf/__init__.py | 7 ++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/tests/test_vdf.py b/tests/test_vdf.py index 5163037..fa49ac1 100644 --- a/tests/test_vdf.py +++ b/tests/test_vdf.py @@ -428,6 +428,41 @@ def test_single_line_empty_block(self): self.assertEqual(vdf.loads(INPUT), EXPECTED) self.assertEqual(vdf.loads(INPUT, escaped=False), EXPECTED) + def test_inline_opening_bracker(self): + INPUT = ''' + "root1" { + "key1" { + } + key2 "value2" + "key3" value3 + } + root2 { } + root3 { + "key1" "value1" + key2 { + + } + "key3" value3 + } + ''' + + EXPECTED = { + 'root1': { + 'key1': {}, + 'key2': 'value2', + 'key3': 'value3', + }, + 'root2': {}, + 'root3': { + 'key1': 'value1', + 'key2': {}, + 'key3': 'value3', + } + } + + self.assertEqual(vdf.loads(INPUT), EXPECTED) + self.assertEqual(vdf.loads(INPUT, escaped=False), EXPECTED) + class testcase_VDF_other(unittest.TestCase): def test_dumps_pretty_output(self): tests = [ diff --git a/vdf/__init__.py b/vdf/__init__.py index 31aebe2..a0b214c 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -90,7 +90,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' r'|(?P(?:(?])+)' - r'|(?P{[ \t]*})' + r'|(?P{[ \t]*)(?P})?' r'))?', flags=re.I) @@ -149,9 +149,10 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): stack[-1][key] = _m if match.group('eblock') is None: - # only expect a bracket if the block is not closed on the same line + # only expect a bracket if it's not already closed or on the same line stack.append(_m) - expect_bracket = True + if match.group('sblock') is None: + expect_bracket = True # we've matched a simple keyvalue pair, map it to the last dict obj in the stack else: From cd22f4fa139bfec43f1f9b1fad4f656805e1dcc3 Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: Tue, 9 Jun 2020 23:16:58 +0100 Subject: [PATCH 10/29] travis: add windows and mac --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0e3b33b..fbd6591 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,12 +51,10 @@ jobs: install: - pip install mock pytest==3.2.1 pytest-cov==2.5.1 - - pip install codecov - pip install coveralls - pip install scrutinizer-ocular script: - PYTHONHASHSEED=0 pytest --cov=vdf tests after_success: - - codecov - coveralls - ocular --data-file ".coverage" From 6219ea1d0b1340be5dc12be284eb3c28108dcac5 Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: Tue, 9 Jun 2020 23:17:22 +0100 Subject: [PATCH 11/29] remove scrutinizer --- .scrutinizer.yml | 17 ----------------- .travis.yml | 2 -- 2 files changed, 19 deletions(-) delete mode 100644 .scrutinizer.yml diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 1f5aea0..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,17 +0,0 @@ -filter: - excluded_paths: - - 'tests/*' - - 'vdf2json/*' -tools: - external_code_coverage: - timeout: 200 - runs: 8 - -build: - nodes: - analysis: - tests: - override: - - command: py-scrutinizer-run - idle_timeout: 300 - diff --git a/.travis.yml b/.travis.yml index fbd6591..5ee80ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,9 +52,7 @@ jobs: install: - pip install mock pytest==3.2.1 pytest-cov==2.5.1 - pip install coveralls - - pip install scrutinizer-ocular script: - PYTHONHASHSEED=0 pytest --cov=vdf tests after_success: - coveralls - - ocular --data-file ".coverage" From acb2b97f59779dc3550d5914d57ab8d6f6a3b77c Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: Tue, 9 Jun 2020 23:37:29 +0100 Subject: [PATCH 12/29] README: add sonar badges --- README.rst | 19 ++++++++++++++----- setup.py | 3 +++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index bba7455..3cef381 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,9 @@ -|pypi| |license| |coverage| |scru| |master_build| +| |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 ``python2.7``, ``python3.3+``, ``pypy`` and ``pypy3``. +Tested and works on ``py2.7``, ``py3.3+``, ``pypy`` and ``pypy3``. VDF is Valve's KeyValue text file format @@ -146,9 +147,17 @@ of reassign the value to the existing key. :target: https://coveralls.io/r/ValvePython/vdf?branch=master :alt: Test coverage -.. |scru| image:: https://scrutinizer-ci.com/g/ValvePython/vdf/badges/quality-score.png?b=master - :target: https://scrutinizer-ci.com/g/ValvePython/vdf/?branch=master - :alt: Scrutinizer score +.. |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://img.shields.io/travis/ValvePython/vdf/master.svg?style=flat&label=master%20build :target: http://travis-ci.org/ValvePython/vdf diff --git a/setup.py b/setup.py index a45b13e..1b7803e 100644 --- a/setup.py +++ b/setup.py @@ -30,6 +30,9 @@ 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: Implementation :: PyPy', ], keywords='valve keyvalue vdf tf2 dota2 csgo', From ecac10d55cdcd1c6d859518e9d040a057af4adbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: 2020年9月26日 11:13:36 +0300 Subject: [PATCH 13/29] Added support for spaces in unquoted values For example, file "csgo\materials\models\props_c17\furniturewooddresser001a.vmt" has these. --- tests/test_vdf.py | 14 ++++++++++++-- vdf/__init__.py | 11 +++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/test_vdf.py b/tests/test_vdf.py index fa49ac1..fabc361 100644 --- a/tests/test_vdf.py +++ b/tests/test_vdf.py @@ -330,6 +330,16 @@ def test_wierd_symbols_for_unquoted(self): self.assertEqual(vdf.loads(INPUT), EXPECTED) self.assertEqual(vdf.loads(INPUT, escaped=False), EXPECTED) + def test_space_for_unquoted(self): + INPUT = 'a b c d \n efg h i\t // j k\n' + EXPECTED= { + 'a': 'b c d', + 'efg': 'h i', + } + + self.assertEqual(vdf.loads(INPUT), EXPECTED) + self.assertEqual(vdf.loads(INPUT, escaped=False), EXPECTED) + def test_merge_multiple_keys_on(self): INPUT = ''' a @@ -437,9 +447,9 @@ def test_inline_opening_bracker(self): "key3" value3 } root2 { } - root3 { + root3 { "key1" "value1" - key2 { + key2 { } "key3" value3 diff --git a/vdf/__init__.py b/vdf/__init__.py index a0b214c..f47cd01 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -89,7 +89,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$%]+))' r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' - r'|(?P(?:(?])+)' + r'|(?P(?:(? ])+)' r'|(?P{[ \t]*)(?P})?' r'))?', flags=re.I) @@ -135,7 +135,14 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): (getattr(fp, 'name', '<%s>' % fp.__class__.__name__), lineno, 0, line)) key = match.group('key') if match.group('qkey') is None else match.group('qkey') - val = match.group('val') if match.group('qval') is None else match.group('qval') + if match.group('qval') is None: + val = match.group('val') + if val is not None: + val = val.rstrip() + if val == "": + val = None + else: + val = match.group('qval') if escaped: key = _unescape(key) From 90648a8c989745d564e0617c589af84aded6aa2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Thu, 3 Dec 2020 14:02:50 +0200 Subject: [PATCH 14/29] Added support for empty quoted keys --- vdf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index f47cd01..8878a50 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -86,7 +86,7 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): stack = [mapper()] expect_bracket = False - re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])+)"|(?P#?[a-z0-9\-\_\\\?$%]+))' + re_keyvalue = re.compile(r'^("(?P(?:\\.|[^\\"])*)"|(?P#?[a-z0-9\-\_\\\?$%]+))' r'([ \t]*(' r'"(?P(?:\\.|[^\\"])*)(?P")?' r'|(?P(?:(? ])+)' From 339f01fb776b546ab6bd28f7255b704f9b9c11d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lassi=20S=C3=A4ike?= Date: Sun, 6 Dec 2020 18:36:34 +0200 Subject: [PATCH 15/29] Refactor value handling --- vdf/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index 8878a50..a1c523a 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -135,14 +135,13 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): (getattr(fp, 'name', '<%s>' % fp.__class__.__name__), lineno, 0, line)) key = match.group('key') if match.group('qkey') is None else match.group('qkey') - if match.group('qval') is None: + val = match.group('qval') + if val is None: val = match.group('val') if val is not None: val = val.rstrip() if val == "": val = None - else: - val = match.group('qval') if escaped: key = _unescape(key) From fb38a256187eeaf4e868ba56624786afd450a4ee Mon Sep 17 00:00:00 2001 From: Rossen <2720787+rossengeorgiev@users.noreply.github.com> Date: 2020年12月17日 19:44:10 +0000 Subject: [PATCH 16/29] Migrate from TravisCI to Github Actions (#30) --- .github/workflows/testing.yml | 57 ++++++++++++++++++++++++++++++++++ .travis.yml | 58 ----------------------------------- README.rst | 4 +-- 3 files changed, 59 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/testing.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml new file mode 100644 index 0000000..601e321 --- /dev/null +++ b/.github/workflows/testing.yml @@ -0,0 +1,57 @@ +name: Tests + +on: + push: + branches: [ master ] + paths-ignore: + - '.gitignore' + - '*.md' + - '*.rst' + - 'LICENSE' + - 'requirements.txt' + - 'vdf2json/**' + pull_request: + branches: [ master ] + paths-ignore: + - '.gitignore' + - '*.md' + - '*.rst' + - 'LICENSE' + - 'requirements.txt' + - 'vdf2json/**' + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + include: + - os: ubuntu-latest + python-version: pypy2 + - os: ubuntu-latest + python-version: pypy3 + steps: + - uses: actions/checkout@v2 + - name: Set up Python Env + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Display Python version + run: python -c "import sys; print(sys.version)" + - name: Install dependencies + run: | + pip install mock pytest==3.2.1 pytest-cov==2.5.1 + pip install coveralls + - name: Run Tests + env: + PYTHONHASHSEED: "0" + run: | + pytest --cov=vdf tests + - name: Coveralls + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + run: | + coveralls diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5ee80ee..0000000 --- a/.travis.yml +++ /dev/null @@ -1,58 +0,0 @@ -language: python -os: linux - -jobs: - include: - - python: 2.7 - - python: 3.4 - - python: 3.5 - - python: 3.6 - - python: 3.7 - - python: 3.8 - - python: "pypy" - - python: "pypy3" -# OSX - - name: OSX Python 2.7 - os: osx - language: shell - before_install: - - cp -fv `which python2` `which python` || true - - cp -fv `which pip2` `which pip` || true - - pip install --upgrade pip - - name: OSX Python 3.7 - os: osx - language: shell - before_install: - - cp -fv `which python3` `which python` || true - - cp -fv `which pip3` `which pip` || true - - pip install --upgrade pip -# Windows - - name: Win Python 3.6 - language: shell - os: windows - before_install: - - choco install python --version 3.6.8 - - python -m pip install --upgrade pip - env: PATH=/c/Python36:/c/Python36/Scripts:$PATH - - name: Win Python 3.7 - language: shell - os: windows - before_install: - - choco install python --version 3.7.4 - - python -m pip install --upgrade pip - env: PATH=/c/Python37:/c/Python37/Scripts:$PATH - - name: Win Python 3.8 - language: shell - os: windows - before_install: - - choco install python --version 3.8.2 - - python -m pip install --upgrade pip - env: PATH=/c/Python38:/c/Python38/Scripts:$PATH - -install: - - pip install mock pytest==3.2.1 pytest-cov==2.5.1 - - pip install coveralls -script: - - PYTHONHASHSEED=0 pytest --cov=vdf tests -after_success: - - coveralls diff --git a/README.rst b/README.rst index 3cef381..0512a77 100644 --- a/README.rst +++ b/README.rst @@ -159,8 +159,8 @@ of reassign the value to the existing key. :target: https://sonarcloud.io/dashboard?id=ValvePython_vdf :alt: SonarCloud Rating -.. |master_build| image:: https://img.shields.io/travis/ValvePython/vdf/master.svg?style=flat&label=master%20build - :target: http://travis-ci.org/ValvePython/vdf +.. |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 From d685734844f6eee6bb6212a42b270b7811abd880 Mon Sep 17 00:00:00 2001 From: Rossen <2720787+rossengeorgiev@users.noreply.github.com> Date: 2020年12月18日 00:52:14 +0000 Subject: [PATCH 17/29] testing workflow: pin setup-python to working version --- .github/workflows/testing.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 601e321..e35ae79 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -35,7 +35,8 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python Env - uses: actions/setup-python@v2 + # FIXME: Use "v2" tag once https://github.com/actions/setup-python/issues/171 is resolved. + - uses: actions/setup-python@v2.1.4 with: python-version: ${{ matrix.python-version }} - name: Display Python version From 0a2a2d6f7041c979e60e80544b3890ce4601cb6a Mon Sep 17 00:00:00 2001 From: Rossen <2720787+rossengeorgiev@users.noreply.github.com> Date: 2020年12月18日 00:54:53 +0000 Subject: [PATCH 18/29] testing: fix syntax for setup-python pin --- .github/workflows/testing.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index e35ae79..5f7d716 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -35,8 +35,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python Env - # FIXME: Use "v2" tag once https://github.com/actions/setup-python/issues/171 is resolved. - - uses: actions/setup-python@v2.1.4 + uses: actions/setup-python@v2.1.4 # FIXME: Use "v2" tag once https://github.com/actions/setup-python/issues/171 is resolved. with: python-version: ${{ matrix.python-version }} - name: Display Python version From 0d6b505cd85199337843e6c5e7dbfa9ce0000dd7 Mon Sep 17 00:00:00 2001 From: Nicholas Malcolm Date: Tue, 7 May 2019 14:55:26 -0400 Subject: [PATCH 19/29] Fix collection deprecation warning Signed-off-by: Nicholas Malcolm --- vdf/vdict.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdf/vdict.py b/vdf/vdict.py index ee71d65..e67afca 100644 --- a/vdf/vdict.py +++ b/vdf/vdict.py @@ -5,7 +5,7 @@ _iter_values = 'values' _range = range _string_type = str - import collections as _c + import collections.abc as _c class _kView(_c.KeysView): def __iter__(self): return self._mapping.iterkeys() From ffe7765e8cb181ff4a4cc7678ea539133c069ae3 Mon Sep 17 00:00:00 2001 From: Rossen <2720787+rossengeorgiev@users.noreply.github.com> Date: 2021年1月19日 00:10:37 +0000 Subject: [PATCH 20/29] Fix coveralls (#32) --- .coveragerc | 9 +++++++++ .github/workflows/testing.yml | 29 ++++++++++++++++++++++------- Makefile | 2 +- requirements.txt | 9 +++++++-- 4 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..c25bdcf --- /dev/null +++ b/.coveragerc @@ -0,0 +1,9 @@ + +# Docs: https://coverage.readthedocs.org/en/latest/config.html + +[run] +branch = False + +# If True, stores relative file paths in data file (needed for Github Actions). +# Using this parameter requires coverage>=5.0 +relative_files = True diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 5f7d716..01630e5 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -35,23 +35,38 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python Env - uses: actions/setup-python@v2.1.4 # FIXME: Use "v2" tag once https://github.com/actions/setup-python/issues/171 is resolved. + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Display Python version run: python -c "import sys; print(sys.version)" - name: Install dependencies run: | - pip install mock pytest==3.2.1 pytest-cov==2.5.1 - pip install coveralls + make init - name: Run Tests env: PYTHONHASHSEED: "0" run: | - pytest --cov=vdf tests - - name: Coveralls + make test + - name: Upload to Coveralls env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + COVERALLS_PARALLEL: true + COVERALLS_FLAG_NAME: "${{ matrix.os }}_${{ matrix.python-version }}" run: | - coveralls + coveralls --service=github + + coveralls: + name: Finish Coveralls + needs: test + runs-on: ubuntu-latest + container: python:3-slim + steps: + - name: Install coveralls + run: | + pip3 install --upgrade coveralls + - name: Send coverage finish to coveralls.io + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + coveralls --finish diff --git a/Makefile b/Makefile index 458427e..464091e 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ init: test: rm -f .coverage vdf/*.pyc tests/*.pyc - PYTHONHASHSEED=0 python -m pytest --cov=vdf tests + PYTHONHASHSEED=0 python -m pytest --tb=short --cov-config .coveragerc --cov=vdf tests pylint: pylint -r n -f colorized vdf || true diff --git a/requirements.txt b/requirements.txt index 27054f2..a5b748b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,8 @@ mock -pytest -pytest-cov + +coverage>=5.0; python_version == '2.7' or python_version>= '3.5' +pytest-cov>=2.7.0; python_version == '2.7' or python_version>= '3.5' + +# coveralls 2.0 has removed support for Python 2.7 and 3.4 +git+https://github.com/andy-maier/coveralls-python.git@andy/add-py27#egg=coveralls; python_version == '2.7' +coveralls>=2.1.2; python_version>= '3.5' From 7cf1ffe07d63b3ca275ffc3fa568b62572514ed0 Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: 2021年1月19日 21:27:26 +0000 Subject: [PATCH 21/29] only dev_requirements.txt --- Makefile | 2 +- requirements.txt => dev_requirements.txt | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename requirements.txt => dev_requirements.txt (100%) diff --git a/Makefile b/Makefile index 464091e..3e7b0ec 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ help: @echo "$$HELPBODY" init: - pip install -r requirements.txt + pip install -r dev_requirements.txt test: rm -f .coverage vdf/*.pyc tests/*.pyc diff --git a/requirements.txt b/dev_requirements.txt similarity index 100% rename from requirements.txt rename to dev_requirements.txt From 146cfdbc69528bec9555cffef0eec22ecf67e3be Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: Mon, 1 Feb 2021 22:09:26 +0000 Subject: [PATCH 22/29] ci: add py3.9 + pypy no cov --- .github/workflows/testing.yml | 13 +++++++++---- Makefile | 8 +++++++- setup.py | 3 +-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 01630e5..f7895c9 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -26,12 +26,15 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9] + no-coverage: [0] include: - os: ubuntu-latest - python-version: pypy2 + python-version: pypy-2.7 + no-coverage: 1 - os: ubuntu-latest - python-version: pypy3 + python-version: pypy-3.6 + no-coverage: 1 steps: - uses: actions/checkout@v2 - name: Set up Python Env @@ -45,10 +48,12 @@ jobs: make init - name: Run Tests env: - PYTHONHASHSEED: "0" + NOCOV: ${{ matrix.no-coverage }} run: | make test - name: Upload to Coveralls + # pypy + concurrenct=gevent not supported in coveragepy. See https://github.com/nedbat/coveragepy/issues/560 + if: matrix.no-coverage == 0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERALLS_PARALLEL: true diff --git a/Makefile b/Makefile index 3e7b0ec..914f5ac 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,15 @@ help: init: pip install -r dev_requirements.txt +COVOPTS = --cov-config .coveragerc --cov=vdf + +ifeq ($(NOCOV), 1) + COVOPTS = +endif + test: rm -f .coverage vdf/*.pyc tests/*.pyc - PYTHONHASHSEED=0 python -m pytest --tb=short --cov-config .coveragerc --cov=vdf tests + PYTHONHASHSEED=0 pytest --tb=short $(COVOPTS) tests pylint: pylint -r n -f colorized vdf || true diff --git a/setup.py b/setup.py index 1b7803e..b40cf4b 100644 --- a/setup.py +++ b/setup.py @@ -26,13 +26,12 @@ 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: Implementation :: PyPy', ], keywords='valve keyvalue vdf tf2 dota2 csgo', From 8cbeff57f2e8dcb0c0972433922c2f470d83e417 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: 2021年2月23日 17:28:02 +0000 Subject: [PATCH 23/29] tests: Avoid problematic use of "is" operator The "is" operator compares objects by identity, not value. It would be valid for a Python implementation to have two different int objects with value 2 (although in practice CPython doesn't). Recent Python versions detect this with a warning: SyntaxWarning: "is" with a literal. Did you mean "=="? Signed-off-by: Simon McVittie --- tests/test_vdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_vdf.py b/tests/test_vdf.py index fabc361..fedb79e 100644 --- a/tests/test_vdf.py +++ b/tests/test_vdf.py @@ -124,7 +124,7 @@ def test_parse_bom_removal(self): result = vdf.loads(vdf.BOMS + '"asd" "123"') self.assertEqual(result, {'asd': '123'}) - if sys.version_info[0] is 2: + if sys.version_info[0] == 2: result = vdf.loads(vdf.BOMS_UNICODE + '"asd" "123"') self.assertEqual(result, {'asd': '123'}) From 2b23d5b8a74f3e1d87e69c82eca7d2eeed26b7d4 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: 2021年2月23日 17:17:49 +0000 Subject: [PATCH 24/29] tests: Try to use unittest.mock from the Python standard library Only fall back to the standalone mock module if the Python version is too old to have it in the standard library. Signed-off-by: Simon McVittie --- dev_requirements.txt | 2 +- tests/test_vdf.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dev_requirements.txt b/dev_requirements.txt index a5b748b..ded0252 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,4 +1,4 @@ -mock +mock; python_version < '3.3' coverage>=5.0; python_version == '2.7' or python_version>= '3.5' pytest-cov>=2.7.0; python_version == '2.7' or python_version>= '3.5' diff --git a/tests/test_vdf.py b/tests/test_vdf.py index fedb79e..a98271f 100644 --- a/tests/test_vdf.py +++ b/tests/test_vdf.py @@ -1,7 +1,11 @@ import unittest -import mock import sys +try: + from unittest import mock +except ImportError: + import mock + try: from StringIO import StringIO except ImportError: From c8c9d236c46c454391230dfd7e80d89d2b57318c Mon Sep 17 00:00:00 2001 From: Chris Angelico Date: 2021年5月20日 16:35:03 +1000 Subject: [PATCH 25/29] Version-mark the dict order issue Dictionary iteration order has been a solved problem since Python 3.6. Since this package supports as far back as 3.3, this could still be a problem, but only for people who are using older versions of Python. Clarifying the language to show this distinction. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 0512a77..c80704e 100644 --- a/README.rst +++ b/README.rst @@ -36,8 +36,8 @@ Problems & solutions 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 due to `hash randomization`_. If key order is important then - I suggest using ``collections.OrderedDict``, or ``vdf.VDFDict``. + 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 ------------- From d2ffefac00d7052194b7a45627245f289e93f315 Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: 2021年5月22日 10:02:14 +0100 Subject: [PATCH 26/29] covert str to mapper for duplicates; #39 --- vdf/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vdf/__init__.py b/vdf/__init__.py index a1c523a..f82f6ef 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -150,6 +150,9 @@ def parse(fp, mapper=dict, merge_duplicate_keys=True, escaped=True): if val is None: if merge_duplicate_keys and key in stack[-1]: _m = stack[-1][key] + # we've descended a level deeper, if value is str, we have to overwrite it to mapper + if not isinstance(_m, mapper): + _m = stack[-1][key] = mapper() else: _m = mapper() stack[-1][key] = _m From a232364d65cfb9dd4aadc20f577ca94950e10b40 Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: 2021年5月22日 10:23:06 +0100 Subject: [PATCH 27/29] add test for previos commmit d2ffefac00d7052194b7a45627245f289e93f315 --- tests/test_vdf.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/test_vdf.py b/tests/test_vdf.py index a98271f..00a245c 100644 --- a/tests/test_vdf.py +++ b/tests/test_vdf.py @@ -477,6 +477,33 @@ def test_inline_opening_bracker(self): self.assertEqual(vdf.loads(INPUT), EXPECTED) self.assertEqual(vdf.loads(INPUT, escaped=False), EXPECTED) + def test_duplicate_key_with_value_from_str_to_mapper(self): + INPUT = r''' + level1 + { + key1 text1 + key2 text2 + } + level1 + { + key2 + { + key3 text3 + } + } + ''' + + EXPECTED = { + "level1": { + "key1": "text1", + "key2": { + "key3": "text3" + } + } + } + + self.assertEqual(vdf.loads(INPUT), EXPECTED) + class testcase_VDF_other(unittest.TestCase): def test_dumps_pretty_output(self): tests = [ From 8104cb27c0b222bd802b69df58204ab389fc714c Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: 2021年5月22日 10:23:40 +0100 Subject: [PATCH 28/29] bump to v3.4 --- vdf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdf/__init__.py b/vdf/__init__.py index f82f6ef..6b47213 100644 --- a/vdf/__init__.py +++ b/vdf/__init__.py @@ -1,7 +1,7 @@ """ Module for deserializing/serializing to and from VDF """ -__version__ = "3.3" +__version__ = "3.4" __author__ = "Rossen Georgiev" import re From d76292623e326fb165fe3bdb684832cdf30959d4 Mon Sep 17 00:00:00 2001 From: Rossen <2720787+rossengeorgiev@users.noreply.github.com> Date: 2022年3月17日 10:28:42 +0000 Subject: [PATCH 29/29] Add py3.10 for testing (#47) --- .github/workflows/testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index f7895c9..1f3c598 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -26,7 +26,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9] + python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, '3.10'] no-coverage: [0] include: - os: ubuntu-latest

AltStyle によって変換されたページ (->オリジナル) /