Created
June 12, 2021 01:43
-
-
Save jonatasrenan/6bdc4b68d63368a0eca7d6f06b244727 to your computer and use it in GitHub Desktop.
A comparison between python's dict libraries to read and write naturally as a JSON parsing.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
A comparison between python's dict libraries to read and write naturally as a JSON parsing. | |
Based on: https://gist.github.com/NelsonMinar/28c5928adbe1f4502af8 | |
Installation: | |
pip install pypi-search addict easydict attrdict dotted-dict dotmap munch python-box | |
""" | |
from typing import Any | |
import addict | |
import easydict | |
import attrdict | |
import dotted_dict | |
import dotmap | |
import munch | |
# import treedict # treedict doesn't work with python3 | |
import box # python-box | |
class DictAnalyzer: | |
source: dict | |
class_: Any | |
package_name: str | |
def __init__(self, source: dict, class_: Any, package_name: str): | |
self.source = source | |
self.class_ = class_ | |
self.package_name = package_name | |
def instance(self): | |
from copy import deepcopy | |
return deepcopy(self.class_(self.source)) | |
def test_bracket_syntax(self): | |
instance = self.instance() | |
assert instance["num"] | |
assert instance["list"][1] | |
assert instance["nested"]["several"]["levels"]["deep"] | |
def test_dot_syntax(self): | |
instance = self.instance() | |
assert instance.num | |
assert instance.list[1] | |
assert instance.nested.several.levels.deep | |
def test_access_missing_elements_using_get_method(self): | |
instance = self.instance() | |
assert instance.get("noObj", {}) == {} | |
assert instance.get("noNum", 1) | |
assert instance.get("noList", []) == [] | |
def test_missing_attribute_is_false(self): | |
instance = self.instance() | |
assert bool(instance.noObj) is False | |
def test_add_element_using_bracket_syntax(self): | |
instance = self.instance() | |
instance["new"] = 5 | |
assert instance.new == 5 | |
def test_add_element_using_dot_syntax(self): | |
instance = self.instance() | |
instance.new = 5 | |
assert instance.new == 5 | |
def test_add_nested_elements_using_bracket_syntax(self): | |
instance = self.instance() | |
instance["other"] = {} | |
instance["other"]["nested"] = {} | |
instance["other"]["nested"]["thing"] = 6 | |
assert instance.other.nested.thing == 6 | |
def test_add_nested_elements_using_dot_syntax(self): | |
instance = self.instance() | |
instance.other = {} | |
instance.other.nested = {} | |
instance.other.nested.thing = 6 | |
assert instance.other.nested.thing == 6 | |
def test_add_nested_elements_without_recursive_initialization(self): | |
instance = self.instance() | |
instance.other.nested.thing = 6 | |
assert instance.other.nested.thing == 6 | |
def test_default_dict_conversion(self): | |
instance = self.instance() | |
assert dict(instance) == self.source | |
def test_serialization(self): | |
from json import dumps | |
instance = self.instance() | |
assert dumps(instance) == dumps(self.source) | |
def test_serialization_after_dict_conversion(self): | |
from json import dumps | |
instance = self.instance() | |
assert dumps(dict(instance)) == dumps(self.source) | |
def instance_size(self): | |
instance = self.instance() | |
return f"{len(instance)}" | |
def json_size(self): | |
from json import dumps | |
instance = self.instance() | |
return f"{len(dumps(instance))}" | |
def title(self): | |
from pypi_search.utils import PyPiPage | |
pypi_page = PyPiPage(self.package_name) | |
stats = "" | |
if pypi_page.response: | |
github_stats = pypi_page.get_github_stats() | |
if github_stats: | |
stats = f"({github_stats['stars']})" | |
return f"{self.package_name}{stats}" | |
def get_test_methods(self): | |
import inspect | |
members = inspect.getmembers(self, predicate=inspect.ismethod) | |
return {name: method for name, method in members if name.startswith('test_')} | |
def tests_results(self): | |
def check(method): | |
try: | |
method() | |
return 'x' | |
except: | |
return '' | |
all_tests = {name: check(method) for name, method in self.get_test_methods().items()} | |
return [self.title(), *all_tests.values(), self.instance_size(), self.json_size()] | |
def tests_names(self): | |
return ["", *self.get_test_methods().keys(), "instance_size", "json_size"] | |
sourceData = { | |
"num": 3.4, | |
"str": "foo", | |
"list": [0, 1, 2, 3], | |
"obj": { | |
"num": 3.4, | |
"str": "foo", | |
"list": [0, 1, 2, 3] | |
}, | |
"nested": { | |
"several": { | |
"levels": { | |
"deep": 5 | |
} | |
} | |
}, | |
"empty_obj": {} | |
} | |
analyzers = [ | |
DictAnalyzer(sourceData, dict, "builtin"), | |
DictAnalyzer(sourceData, addict.Dict, "addict"), | |
DictAnalyzer(sourceData, easydict.EasyDict, "easydict"), | |
DictAnalyzer(sourceData, attrdict.AttrDict, "attrdict"), | |
DictAnalyzer(sourceData, dotted_dict.DottedDict, "dotted-dict"), | |
DictAnalyzer(sourceData, dotmap.DotMap, "dotmap"), | |
DictAnalyzer(sourceData, munch.Munch, "munch"), | |
DictAnalyzer(sourceData, box.Box, "python-box"), | |
] | |
results = [analyzer.tests_results() for analyzer in analyzers] | |
results.sort(key=lambda l: sum([1 for i in l if i])) | |
table = [analyzers[0].tests_names(), *results] | |
transposed_table = list(map(list, zip(*table))) | |
# Print Table | |
print("| " + " | ".join(transposed_table[0]) + " |") # titles | |
print("| " + " | ".join([":-:" for _ in range(len(transposed_table[0]))])) | |
for line in transposed_table[1:]: | |
print(f"| {line[0] } | " + " | ".join(line[1:]) + " |") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
python 3.9.12