From 893892215872b0092df9da540762f510319ee32e Mon Sep 17 00:00:00 2001 From: RadarJam Date: Sat, 23 Sep 2023 17:17:20 +0200 Subject: [PATCH 1/7] Test cases --- tests/core/mocksettings.py | 6 ++++++ tests/core/test_settings.py | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/core/mocksettings.py create mode 100644 tests/core/test_settings.py diff --git a/tests/core/mocksettings.py b/tests/core/mocksettings.py new file mode 100644 index 0000000..b44f8d3 --- /dev/null +++ b/tests/core/mocksettings.py @@ -0,0 +1,6 @@ +foo = "bar" + +d = { + "k1": "v1", + "k2":{"a":"a","b":"b"} +} \ No newline at end of file diff --git a/tests/core/test_settings.py b/tests/core/test_settings.py new file mode 100644 index 0000000..c8381a6 --- /dev/null +++ b/tests/core/test_settings.py @@ -0,0 +1,26 @@ +from tests.module_helper import PyttmanInternalBaseTestCase +from pyttman.core.internals import Settings + +from importlib import import_module +from . import mocksettings + +class PyttmanInternalSettingsPyttmanApp(PyttmanInternalBaseTestCase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + settings_names = [i for i in dir(mocksettings) + if not i.startswith("_")] + settings_config = {name: getattr(mocksettings, name) + for name in settings_names} + self.settings = Settings(**settings_config) + + def test_read_settings_with_dictionary(self): + + self.assertTrue(self.settings.d.k2.a == "a") + self.assertTrue(self.settings.d["k2"].a == "a") + self.assertTrue(self.settings.d["k2"]["a"] == "a") + + self.assertTrue(self.settings.d.k1 == "v1") + self.assertTrue(self.settings.d["k1"] == "v1") + + self.assertTrue(self.settings.foo == "bar") + From 483f5ffdafde3d8cbf7c8af2f9d7e3b6d3f6b86b Mon Sep 17 00:00:00 2001 From: RadarJam Date: Sat, 23 Sep 2023 17:18:35 +0200 Subject: [PATCH 2/7] Dot notation can be used to read dicts in settings.py --- pyttman/core/internals.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/pyttman/core/internals.py b/pyttman/core/internals.py index 9a4ac97..401b303 100644 --- a/pyttman/core/internals.py +++ b/pyttman/core/internals.py @@ -5,6 +5,9 @@ from dataclasses import dataclass, field from datetime import datetime from typing import Any +import json +from collections import UserDict + import pyttman from pyttman.core.containers import MessageMixin, Reply @@ -32,6 +35,12 @@ def depr_graceful(message: str, version: str): out = f"{message} - This was deprecated in version {version}." warnings.warn(out, DeprecationWarning) +class CustomUserDict(UserDict): + + # constructor + def __init__(self, dictionary): + self.data = dictionary + self.__dict__.update(dictionary) class Settings: """ @@ -60,10 +69,20 @@ def __init__(self, **kwargs): self.LOG_FORMAT: str | None = None self.LOG_TO_STDOUT: bool = False - [setattr(self, k, v) for k, v in kwargs.items() + [self.__set_attr(k, v) for k, v in kwargs.items() if not inspect.ismodule(v) and not inspect.isfunction(v)] + def __set_attr(self, k, v): + tmp = v + if isinstance(v, dict): + tmp = self.__dict2obj(v) + + setattr(self, k, tmp) + + def __dict2obj(self, dictionary): + return json.loads(json.dumps(dictionary), object_hook=CustomUserDict) + def __repr__(self): _attrs = {name: value for name, value in self.__dict__.items()} return f"Settings({_attrs})" From 480cdc35a1815ad850b570624bb41ce3a0537766 Mon Sep 17 00:00:00 2001 From: RadarJam Date: Sun, 24 Sep 2023 15:36:02 +0200 Subject: [PATCH 3/7] Removed Reduntant class --- pyttman/core/internals.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pyttman/core/internals.py b/pyttman/core/internals.py index 401b303..c3017fd 100644 --- a/pyttman/core/internals.py +++ b/pyttman/core/internals.py @@ -35,13 +35,6 @@ def depr_graceful(message: str, version: str): out = f"{message} - This was deprecated in version {version}." warnings.warn(out, DeprecationWarning) -class CustomUserDict(UserDict): - - # constructor - def __init__(self, dictionary): - self.data = dictionary - self.__dict__.update(dictionary) - class Settings: """ Dataclass holding settings configured in the settings.py @@ -57,7 +50,8 @@ class Settings: aren't valid settings. """ - def __init__(self, **kwargs): + def __init__(self, dictionary={}, **kwargs): + self.__dict__.update(dictionary) self.APPEND_LOG_FILES: bool = True self.MIDDLEWARE: dict | None = None self.ABILITIES: list | None = None @@ -73,15 +67,18 @@ def __init__(self, **kwargs): if not inspect.ismodule(v) and not inspect.isfunction(v)] + def __getitem__(self, item): + return self.__dict__[item] + def __set_attr(self, k, v): tmp = v if isinstance(v, dict): tmp = self.__dict2obj(v) setattr(self, k, tmp) - + def __dict2obj(self, dictionary): - return json.loads(json.dumps(dictionary), object_hook=CustomUserDict) + return json.loads(json.dumps(dictionary), object_hook=Settings) def __repr__(self): _attrs = {name: value for name, value in self.__dict__.items()} From 6242f9b6d0aa168a3da2bdbabe2d588048a0eba6 Mon Sep 17 00:00:00 2001 From: RadarJam Date: Sun, 24 Sep 2023 15:37:41 +0200 Subject: [PATCH 4/7] Renamed method and set it as a class method --- pyttman/core/internals.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyttman/core/internals.py b/pyttman/core/internals.py index c3017fd..9066ecd 100644 --- a/pyttman/core/internals.py +++ b/pyttman/core/internals.py @@ -73,17 +73,17 @@ def __getitem__(self, item): def __set_attr(self, k, v): tmp = v if isinstance(v, dict): - tmp = self.__dict2obj(v) + tmp = Settings._dict_to_object(v) setattr(self, k, tmp) - def __dict2obj(self, dictionary): - return json.loads(json.dumps(dictionary), object_hook=Settings) - def __repr__(self): _attrs = {name: value for name, value in self.__dict__.items()} return f"Settings({_attrs})" + @staticmethod + def _dict_to_object(dictionary): + return json.loads(json.dumps(dictionary), object_hook=Settings) def _generate_name(name): """ From b30d1abd26f0c16a7c4d289bc5f61b648e927c11 Mon Sep 17 00:00:00 2001 From: RadarJam Date: Sun, 24 Sep 2023 15:55:45 +0200 Subject: [PATCH 5/7] Test suite is now using pytest test fixtures --- tests/core/test_settings.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tests/core/test_settings.py b/tests/core/test_settings.py index c8381a6..405dd78 100644 --- a/tests/core/test_settings.py +++ b/tests/core/test_settings.py @@ -4,23 +4,26 @@ from importlib import import_module from . import mocksettings -class PyttmanInternalSettingsPyttmanApp(PyttmanInternalBaseTestCase): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - settings_names = [i for i in dir(mocksettings) - if not i.startswith("_")] - settings_config = {name: getattr(mocksettings, name) - for name in settings_names} - self.settings = Settings(**settings_config) +import pytest - def test_read_settings_with_dictionary(self): - - self.assertTrue(self.settings.d.k2.a == "a") - self.assertTrue(self.settings.d["k2"].a == "a") - self.assertTrue(self.settings.d["k2"]["a"] == "a") - - self.assertTrue(self.settings.d.k1 == "v1") - self.assertTrue(self.settings.d["k1"] == "v1") +@pytest.fixture +def mockSettings(): + settings_names = [i for i in dir(mocksettings) + if not i.startswith("_")] + settings_config = {name: getattr(mocksettings, name) + for name in settings_names} + + return Settings(**settings_config) + +def test_read_settings_with_dictionary(mockSettings): + settings = mockSettings + + assert settings.d.k2.a == "a" + assert settings.d["k2"].a == "a" + assert settings.d["k2"]["a"] == "a" + + assert settings.d.k1 == "v1" + assert settings.d["k1"] == "v1" - self.assertTrue(self.settings.foo == "bar") + assert settings.foo == "bar" From a9c43287e8f8ba4bae78e970d12085260ec76b89 Mon Sep 17 00:00:00 2001 From: RadarJam Date: Sun, 24 Sep 2023 16:09:01 +0200 Subject: [PATCH 6/7] Test Fixture generates MockSettings --- tests/core/mocksettings.py | 6 ------ tests/core/test_settings.py | 33 ++++++++++++++++++--------------- 2 files changed, 18 insertions(+), 21 deletions(-) delete mode 100644 tests/core/mocksettings.py diff --git a/tests/core/mocksettings.py b/tests/core/mocksettings.py deleted file mode 100644 index b44f8d3..0000000 --- a/tests/core/mocksettings.py +++ /dev/null @@ -1,6 +0,0 @@ -foo = "bar" - -d = { - "k1": "v1", - "k2":{"a":"a","b":"b"} -} \ No newline at end of file diff --git a/tests/core/test_settings.py b/tests/core/test_settings.py index 405dd78..a225584 100644 --- a/tests/core/test_settings.py +++ b/tests/core/test_settings.py @@ -2,28 +2,31 @@ from pyttman.core.internals import Settings from importlib import import_module -from . import mocksettings - import pytest @pytest.fixture def mockSettings(): - settings_names = [i for i in dir(mocksettings) - if not i.startswith("_")] - settings_config = {name: getattr(mocksettings, name) - for name in settings_names} + + mock_settings = { + "d":{ + "k1":"v1", + "k2":{ + "a":"a", + "b":"b" + } + }, + "foo":"bar" + } - return Settings(**settings_config) + return Settings(**mock_settings) def test_read_settings_with_dictionary(mockSettings): - settings = mockSettings - - assert settings.d.k2.a == "a" - assert settings.d["k2"].a == "a" - assert settings.d["k2"]["a"] == "a" + assert mockSettings.d.k2.a == "a" + assert mockSettings.d["k2"].a == "a" + assert mockSettings.d["k2"]["a"] == "a" - assert settings.d.k1 == "v1" - assert settings.d["k1"] == "v1" + assert mockSettings.d.k1 == "v1" + assert mockSettings.d["k1"] == "v1" - assert settings.foo == "bar" + assert mockSettings.foo == "bar" From 305697620a9a4068366c1bb2f2ad3ca159203c86 Mon Sep 17 00:00:00 2001 From: RadarJam Date: Mon, 25 Sep 2023 18:36:46 +0200 Subject: [PATCH 7/7] Fixed memory leak and renamed method --- pyttman/core/internals.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyttman/core/internals.py b/pyttman/core/internals.py index 9066ecd..97b09ca 100644 --- a/pyttman/core/internals.py +++ b/pyttman/core/internals.py @@ -50,7 +50,9 @@ class Settings: aren't valid settings. """ - def __init__(self, dictionary={}, **kwargs): + def __init__(self, dictionary=None, **kwargs): + if dictionary is None: + dictionary = {} self.__dict__.update(dictionary) self.APPEND_LOG_FILES: bool = True self.MIDDLEWARE: dict | None = None @@ -63,14 +65,14 @@ def __init__(self, dictionary={}, **kwargs): self.LOG_FORMAT: str | None = None self.LOG_TO_STDOUT: bool = False - [self.__set_attr(k, v) for k, v in kwargs.items() + [self._set_attr(k, v) for k, v in kwargs.items() if not inspect.ismodule(v) and not inspect.isfunction(v)] def __getitem__(self, item): return self.__dict__[item] - def __set_attr(self, k, v): + def _set_attr(self, k, v): tmp = v if isinstance(v, dict): tmp = Settings._dict_to_object(v)