Merge pull request #366 from oddstr13/pr-json-filter-1

Filter keys containing None values from dictionaries returned from the server
This commit is contained in:
mcarlton00 2020-08-21 17:43:52 -04:00 committed by GitHub
commit 4e2c8a0af3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 214 additions and 26 deletions

View file

@ -1,9 +1,11 @@
import xml.etree.ElementTree as ET
import yaml
import sys
import os
from datetime import datetime
import yaml
def indent(elem, level=0):
'''
Nicely formats output xml with newlines and spaces
@ -23,6 +25,7 @@ def indent(elem, level=0):
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
try:
py_version = sys.argv[1]
except IndexError:

66
.gitignore vendored
View file

@ -1,12 +1,72 @@
*.pyo
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
__local__/
machine_guid
/resources/media/Thumbs.db
Thumbs.db
.idea/
.DS_Store
.vscode/
pyinstrument/
pyinstrument_cext.so
# Now managed by templates
addon.xml
*.log

View file

@ -17,8 +17,8 @@ sys.path.insert(0, __base__)
#################################################################################################
from entrypoint import Context # noqa: F402
from helper import LazyLogger # noqa: F402
from entrypoint import Context # noqa: E402
from helper import LazyLogger # noqa: E402
#################################################################################################

View file

@ -17,8 +17,8 @@ sys.path.insert(0, __base__)
#################################################################################################
from entrypoint import Context # noqa: F402
from helper import LazyLogger # noqa: F402
from entrypoint import Context # noqa: E402
from helper import LazyLogger # noqa: E402
#################################################################################################

View file

@ -17,8 +17,8 @@ sys.path.insert(0, __base__)
#################################################################################################
from entrypoint import Events # noqa: F402
from helper import LazyLogger # noqa: F402
from entrypoint import Events # noqa: E402
from helper import LazyLogger # noqa: E402
#################################################################################################

View file

@ -224,6 +224,7 @@ def get_library_items(library_id, item_type):
return _get(url, params)
def get_albums_by_artist(artist_id, basic=False):
params = {

View file

@ -11,6 +11,7 @@ from six import string_types, ensure_str
from helper.utils import JsonDebugPrinter
from helper import LazyLogger
from helper.exceptions import HTTPException
from jellyfin.utils import clean_none_dict_values
#################################################################################################
@ -161,7 +162,7 @@ class HTTP(object):
LOG.debug("---<[ http ][%s ms]", elapsed)
LOG.debug(JsonDebugPrinter(response))
return response
return clean_none_dict_values(response)
except ValueError:
return

View file

@ -0,0 +1,43 @@
from six import string_types
from six.moves import collections_abc
def clean_none_dict_values(obj):
"""
Recursively remove keys with a value of None
"""
if not isinstance(obj, collections_abc.Iterable) or isinstance(obj, string_types):
return obj
queue = [obj]
while queue:
item = queue.pop()
if isinstance(item, collections_abc.Mapping):
mutable = isinstance(item, collections_abc.MutableMapping)
remove = []
for key, value in item.items():
if value is None and mutable:
remove.append(key)
elif isinstance(value, string_types):
continue
elif isinstance(value, collections_abc.Iterable):
queue.append(value)
if mutable:
# Remove keys with None value
for key in remove:
item.pop(key)
elif isinstance(item, collections_abc.Iterable):
for value in item:
if value is None or isinstance(value, string_types):
continue
elif isinstance(value, collections_abc.Iterable):
queue.append(value)
return obj

13
requirements-dev.txt Normal file
View file

@ -0,0 +1,13 @@
setuptools >= 44.1.1 # Old setuptools causes script.module.addon.signals to fail installing
six >= 1.13
python-dateutil >= 2.8.1
requests >= 2.22
futures >= 2.2; python_version < '3.0'
git+https://github.com/oddstr13/Kodistubs@python3 # Kodistubs >= 18
git+https://github.com/romanvm/kodi.six
git+https://github.com/ruuk/script.module.addon.signals
pytest >= 4.6.11
coverage >= 5.2
flake8 >= 3.8
flake8-import-order >= 0.18

View file

@ -18,9 +18,9 @@ sys.path.insert(0, __base__)
#################################################################################################
from entrypoint import Service # noqa: F402
from helper.utils import settings # noqa: F402
from helper import LazyLogger # noqa: F402
from entrypoint import Service # noqa: E402
from helper.utils import settings # noqa: E402
from helper import LazyLogger # noqa: E402
#################################################################################################

0
tests/__init__.py Normal file
View file

View file

@ -0,0 +1,51 @@
import sys
import pytest
sys.path.insert(0, 'jellyfin_kodi')
from jellyfin.utils import clean_none_dict_values # noqa: E402
@pytest.mark.parametrize("obj,expected", [
(None, None),
([None, 1, 2, 3, None, 4], [None, 1, 2, 3, None, 4]),
({'foo': None, 'bar': 123}, {'bar': 123}),
({
'dict': {
'empty': None,
'string': "Hello, Woorld!",
},
'number': 123,
'list': [
None,
123,
"foo",
{
'empty': None,
'number': 123,
'string': "foo",
'list': [],
'dict': {},
}
]
}, {
'dict': {
'string': "Hello, Woorld!",
},
'number': 123,
'list': [
None,
123,
"foo",
{
'number': 123,
'string': "foo",
'list': [],
'dict': {},
}
]
}),
])
def test_clean_none_dict_values(obj, expected):
assert clean_none_dict_values(obj) == expected

16
tox.ini
View file

@ -6,3 +6,19 @@ extend-ignore =
I202
per-file-ignores =
*/__init__.py: F401
[pytest]
minversion = 4.6
testpaths =
tests
[coverage:run]
source =
jellyfin_kodi
context.py
context_play.py
default.py
service.py
.config/generate_xml.py
omit = tests/*
command_line = -m pytest