From 408a811b822098d04335430738e6d5cd5d55e3fe Mon Sep 17 00:00:00 2001 From: cclecle Date: Sun, 26 Mar 2023 02:12:13 +0100 Subject: [PATCH] improve test and doc --- docs-static/usage.md | 29 +++- src/pychangelogfactory/__init__.py | 2 +- src/pychangelogfactory/changelogfactory.py | 67 ++++++--- test/test_changelogfactory.py | 150 +++++++++++++++++++-- 4 files changed, 214 insertions(+), 34 deletions(-) diff --git a/docs-static/usage.md b/docs-static/usage.md index 8550bd6..f8368f7 100644 --- a/docs-static/usage.md +++ b/docs-static/usage.md @@ -168,9 +168,9 @@ hdlr.RegisterFormater(ChangeLogFormater_others) ### Inject custom formater module-wide ``` py -from pychangelogfactory import ChangeLogFormater,ChangeLogFormaterRecordType +from pychangelogfactory import ChangeLogFormater,ChangelogFormaterRecordType -@ChangeLogFormaterRecordType +@ChangelogFormaterRecordType class ChangeLogFormater_others(ChangeLogFormater): """My formater""" @@ -184,7 +184,7 @@ hdlr = ChangeLogFactory() ``` /// note | Scope -This will register your new formater for all next new factories +This will register your new formater for all next new factories, maybe not only in your own code ! /// ### Test @@ -207,5 +207,24 @@ print(changelog) > need 42 coffee - - +### revert changes +#### Reset to original list class-wise (all modules): +``` py +ChangeLogFactory.ResetFormaterList() +... +``` +#### Reset to original list instance-wise: +``` py +hdlr = ChangeLogFactory() +hdlr.ResetFormaterList() +... +``` +#### Removing a specific formater: +``` py +hdlr = ChangeLogFactory() +hdlr.unRegisterFormater(ChangeLogFormater_others) +... +``` +/// warning +There is no way to remove a specific formater class-wise (all modules). +/// diff --git a/src/pychangelogfactory/__init__.py b/src/pychangelogfactory/__init__.py index 18d2fd7..3a37726 100644 --- a/src/pychangelogfactory/__init__.py +++ b/src/pychangelogfactory/__init__.py @@ -20,4 +20,4 @@ except PackageNotFoundError: # pragma: no cover warnings.warn("can not read __version__, assuming local test context, setting it to ?.?.?") __version__ = "?.?.?" -from .changelogfactory import ChangeLogFactory, ChangeLogFormaterRecordType, ChangeLogFormater +from .changelogfactory import ChangeLogFactory, ChangelogFormaterRecordType, ChangeLogFormater diff --git a/src/pychangelogfactory/changelogfactory.py b/src/pychangelogfactory/changelogfactory.py index 22f732d..ad90e70 100644 --- a/src/pychangelogfactory/changelogfactory.py +++ b/src/pychangelogfactory/changelogfactory.py @@ -18,9 +18,11 @@ from __future__ import annotations import re from abc import ABC +_savedFormaterList = set() -def ChangeLogFormaterRecordType(Klass: type) -> type: - """Decorator helper function to register interface implementation in factory + +def ChangelogFormaterRecordType(Klass: type) -> type: + """Decorator function that registers formater implementation in factory Args: Klass: class to register in the factory Returns: @@ -29,6 +31,16 @@ def ChangeLogFormaterRecordType(Klass: type) -> type: return Klass +def _ChangelogFormaterRecordType(Klass: type) -> type: + """Internal decorator function that registers formater implementation in factory + Args: + Klass: class to register in the factory + Returns: + untouched class""" + _savedFormaterList.add(Klass) + return ChangelogFormaterRecordType(Klass) + + class ChangeLogFormater(ABC): prefix: str = "^\s+" @@ -55,11 +67,11 @@ class ChangeLogFormater(ABC): /// """ - self._lines: list[str] = [] + self._lines = [] def Clear(self) -> None: """Clear the formater content""" - self._lines: list[str] = [] + self._lines = [] def PushLine(self, ChangelogString: str) -> None: """Push a new line in the formater @@ -130,7 +142,7 @@ class ChangeLogFactory: """The main changelog class""" ar_FormaterKlass: set[type[ChangeLogFormater]] = set() - ar_Formater: dict[ChangeLogFormater] = dict() + ar_Formater: None | dict[ChangeLogFormater] = None checkCommentPattern: str = r"^[ \t]*(?:\/\/|#)" def __init__(self, ChangelogString: None | str = None): @@ -139,31 +151,55 @@ class ChangeLogFactory: Args: ChangelogString: optionnal input string to start with """ - for FormaterKlass in ChangeLogFactory.ar_FormaterKlass: + self.ar_Formater = dict() + self.ar_FormaterKlass = self.ar_FormaterKlass.copy() + + for FormaterKlass in self.ar_FormaterKlass: self.ar_Formater[FormaterKlass.__name__] = FormaterKlass() if isinstance(ChangelogString, str): self.ProcessFullChangelog(ChangelogString) + def ResetFormaterList(self=None) -> None | ChangeLogFactory: + """Reset the formater class list to original + + This method can be call both from class or from instance. + + > If call from class it will reset the whole list. + + > If call from instance only the instance will be reseted. + + Returns: + self for convenience or None if call from class + """ + if self is not None: + self.ar_FormaterKlass = _savedFormaterList.copy() + self.ar_Formater = dict() + for FormaterKlass in self.ar_FormaterKlass: + self.ar_Formater[FormaterKlass.__name__] = FormaterKlass() + return self + else: + ChangeLogFactory.ar_FormaterKlass = _savedFormaterList.copy() + def RegisterFormater(self, FormaterKlass: ChangeLogFormater) -> None: - """Register a new formater + """Register a new formater in the current instance Args: FormaterKlass: class of the formater to be added Returns: - self class for convenience + self for convenience """ self.ar_FormaterKlass.add(FormaterKlass) self.ar_Formater[FormaterKlass.__name__] = FormaterKlass() return self def unRegisterFormater(self, FormaterKlass: ChangeLogFormater) -> None: - """Register a new formater + """unRegister a new formater in the current instance Args: - FormaterKlass: class of the formater to be removed + FormaterKlass: class of the formater to be dropped Returns: - self class for convenience + self for convenience """ self.ar_FormaterKlass.remove(FormaterKlass) del self.ar_Formater[FormaterKlass.__name__] @@ -172,7 +208,7 @@ class ChangeLogFactory: def Clear(self) -> ChangeLogFactory: """Clear internal memory Returns: - self class for convenience + self for convenience """ for formater in self.ar_Formater.values(): formater.Clear() @@ -230,7 +266,7 @@ class ChangeLogFactory: Args: RawChangelogMessage: The full raw changelog (merged commit-history) Returns: - self class for convenience + self for convenience """ Lines2ndRound = [] @@ -328,9 +364,10 @@ for RecordType, Config in { }, ) ChangeLogFactory.ar_FormaterKlass.add(_tmp) + _savedFormaterList.add(_tmp) -@ChangeLogFormaterRecordType +@_ChangelogFormaterRecordType class ChangeLogFormater_revert(ChangeLogFormater): """Revert scope formater""" @@ -350,7 +387,7 @@ class ChangeLogFormater_revert(ChangeLogFormater): return full_lines -@ChangeLogFormaterRecordType +@_ChangelogFormaterRecordType class ChangeLogFormater_others(ChangeLogFormater): """Others / unknown scope formater""" diff --git a/test/test_changelogfactory.py b/test/test_changelogfactory.py index 1ba3db4..75db754 100644 --- a/test/test_changelogfactory.py +++ b/test/test_changelogfactory.py @@ -8,12 +8,15 @@ import unittest -from src import pychangelogfactory +from src.pychangelogfactory import ChangeLogFormater, ChangeLogFactory, ChangelogFormaterRecordType class Testtest_module(unittest.TestCase): + def setUp(self): + ChangeLogFactory.ResetFormaterList() + def simplegeneration(self, inputstr, teststrs: list[str]): - hdlr = pychangelogfactory.ChangeLogFactory() + hdlr = ChangeLogFactory() hdlr.ProcessFullChangelog(inputstr) changelog = hdlr.RenderFullChangelog() for test in teststrs: @@ -22,7 +25,7 @@ class Testtest_module(unittest.TestCase): def test_simplegeneration_ignored2(self): raw = "break: testbreak break" + "\n" + "#doc: testdoc doc" + "\n" + "#style: teststyle beautify" + "\n" + "//test: testtest check" - hdlr = pychangelogfactory.ChangeLogFactory(raw) + hdlr = ChangeLogFactory(raw) changelog = hdlr.RenderFullChangelog() self.assertIn("testbreak", changelog) @@ -33,7 +36,7 @@ class Testtest_module(unittest.TestCase): def test_simplegeneration_ignored(self): raw = "break: testbreak" + "\n" + "#doc: testdoc" + "\n" + "#style: teststyle" + "\n" + "//test: testtest" - hdlr = pychangelogfactory.ChangeLogFactory(raw) + hdlr = ChangeLogFactory(raw) changelog = hdlr.RenderFullChangelog() self.assertIn("testbreak", changelog) self.assertNotIn("testdoc", changelog) @@ -42,7 +45,7 @@ class Testtest_module(unittest.TestCase): def test_simplegeneration_order(self): raw = "break: testbreak" + "\n" + "doc: testdoc" + "\n" + "style: teststyle" + "\n" + "test: testtest" - hdlr = pychangelogfactory.ChangeLogFactory(raw) + hdlr = ChangeLogFactory(raw) changelog = hdlr.RenderFullChangelog().splitlines() self.assertIn("testbreak", changelog[1]) self.assertIn("teststyle", changelog[3]) @@ -144,28 +147,40 @@ class Testtest_module(unittest.TestCase): # fmt: on def test_sample(self): - hdlr = pychangelogfactory.ChangeLogFactory(self.raw_changelog) + hdlr = ChangeLogFactory(self.raw_changelog) changelog = hdlr.RenderFullChangelog(include_unknown=True) self.assertEqual(changelog, self.expected_formated) def test_sample_aio(self): - changelog = pychangelogfactory.ChangeLogFactory(self.raw_changelog).RenderFullChangelog(include_unknown=True) - print(changelog) + changelog = ChangeLogFactory(self.raw_changelog).RenderFullChangelog(include_unknown=True) self.assertEqual(changelog, self.expected_formated) def test_sample_exploded(self): - hdlr = pychangelogfactory.ChangeLogFactory() + hdlr = ChangeLogFactory() hdlr.ProcessFullChangelog(self.raw_changelog) changelog = hdlr.RenderFullChangelog(include_unknown=True) self.assertEqual(changelog, self.expected_formated) + def test_sample_clear(self): + hdlr = ChangeLogFactory() + hdlr.ProcessFullChangelog(self.raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, self.expected_formated) + hdlr.Clear() + changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, "") + class Testtest_module_othercontext(unittest.TestCase): + def setUp(self): + ChangeLogFactory.ResetFormaterList() + def test_custom(self): + """ + 1st PART: register a global custom formater + """ - from src.pychangelogfactory import ChangeLogFormater, ChangeLogFormaterRecordType, ChangeLogFactory - - @ChangeLogFormaterRecordType + @ChangelogFormaterRecordType class ChangeLogFormater_TEST(ChangeLogFormater): """My formater""" @@ -179,7 +194,7 @@ class Testtest_module_othercontext(unittest.TestCase): "foo modification in my file\n" "need 42 coffee\n" ) - expected_formated = ( + expected_formated_orig = ( "#### My Title :\n" "> add a nice feature to the project\n" "> foo modification in my file\n" @@ -189,4 +204,113 @@ class Testtest_module_othercontext(unittest.TestCase): hdlr = ChangeLogFactory(raw_changelog) changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, expected_formated_orig) + + """ + 2nd PART: cheking the custom formater is still here after new object creation + """ + + hdlr = ChangeLogFactory(raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, expected_formated_orig) + + """ + 3rd PART: removing the custom formater at runtime + """ + + hdlr = ChangeLogFactory() + hdlr.unRegisterFormater(ChangeLogFormater_TEST) + hdlr.ProcessFullChangelog(raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) + + # fmt: off + expected_formated = ( + "#### Features :sparkles: :\n" + "> mytag: add a nice feature to the project\n" + "#### Others :question: :\n" + "> foo modification in my file\n" + "> need 42 coffee\n" + ) + # fmt: on + + self.assertEqual(changelog, expected_formated) + + """ + 4th PART: checking it is back when create new obj + """ + + hdlr = ChangeLogFactory() + hdlr.ProcessFullChangelog(raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, expected_formated_orig) + + """ + 3.1rd PART: removing the custom formater at runtime + """ + + hdlr = ChangeLogFactory() + hdlr.ResetFormaterList() + hdlr.ProcessFullChangelog(raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, expected_formated) + + """ + 4.1th PART: checking it is back when create new obj + """ + + hdlr = ChangeLogFactory() + hdlr.ProcessFullChangelog(raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, expected_formated_orig) + + """ + 5th PART: reseting class list globally + """ + ChangeLogFactory.ResetFormaterList() + hdlr = ChangeLogFactory() + hdlr.ProcessFullChangelog(raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, expected_formated) + + """ + 6th PART: checking it is still not here + """ + hdlr = ChangeLogFactory() + hdlr.ProcessFullChangelog(raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) + self.assertEqual(changelog, expected_formated) + + +class Testtest_module_othercontext2(unittest.TestCase): + def setUp(self): + ChangeLogFactory.ResetFormaterList() + + def test_custom2(self): + class ChangeLogFormater_TEST2(ChangeLogFormater): + """My formater""" + + prefix: str = "mytag" + title: str = "My Title 2:" + keywords: list[str] = ["foo", "42"] + priority: int = 10 + + # fmt: off + raw_changelog = ("mytag: add a nice feature to the project\n" + "foo modification in my file\n" + "need 42 coffee\n" + ) + expected_formated = ( + "#### My Title 2:\n" + "> add a nice feature to the project\n" + "> foo modification in my file\n" + "> need 42 coffee\n" + ) + # fmt: on + + hdlr = ChangeLogFactory() + + hdlr.RegisterFormater(ChangeLogFormater_TEST2) + + hdlr.ProcessFullChangelog(raw_changelog) + changelog = hdlr.RenderFullChangelog(include_unknown=True) self.assertEqual(changelog, expected_formated)