From 1a94daaea20b3cdbd5a59e7a17b0706a4a4c310b Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 25 Jun 2025 05:18:44 -0400 Subject: [PATCH 1/9] Attempts to fix olsg import in unit tests --- pyproject.toml | 2 +- tests/test_oslg.py | 2 +- uv.lock | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 uv.lock diff --git a/pyproject.toml b/pyproject.toml index bfb811c..c19eac2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "oslg" -version = "0.3.0a1" +version = "0.3.0a2" description = "OpenStudio SDK logger for Python" readme = "README.md" requires-python = ">=3.2" diff --git a/tests/test_oslg.py b/tests/test_oslg.py index 6e56d14..89ee08a 100644 --- a/tests/test_oslg.py +++ b/tests/test_oslg.py @@ -31,7 +31,7 @@ sys.path.append("./src/oslg") import unittest -import oslg +from oslg import oslg DBG = oslg.CN.DEBUG INF = oslg.CN.INFO diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..bdcb590 --- /dev/null +++ b/uv.lock @@ -0,0 +1,8 @@ +version = 1 +revision = 2 +requires-python = ">=3.2" + +[[package]] +name = "oslg" +version = "0.3.0a2" +source = { editable = "." } From 8188dd14ea6b362f76bedfe0563232f9ba11ddeb Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 25 Jun 2025 05:20:49 -0400 Subject: [PATCH 2/9] Reverts oslg import in unit tests --- tests/test_oslg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_oslg.py b/tests/test_oslg.py index 89ee08a..6e56d14 100644 --- a/tests/test_oslg.py +++ b/tests/test_oslg.py @@ -31,7 +31,7 @@ sys.path.append("./src/oslg") import unittest -from oslg import oslg +import oslg DBG = oslg.CN.DEBUG INF = oslg.CN.INFO From 03542a390251433eacea427225f21683ae390a52 Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 25 Jun 2025 06:05:44 -0400 Subject: [PATCH 3/9] Changes import path for unit tests --- tests/test_oslg.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_oslg.py b/tests/test_oslg.py index 6e56d14..eca9c09 100644 --- a/tests/test_oslg.py +++ b/tests/test_oslg.py @@ -27,11 +27,13 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import sys -sys.path.append("./src/oslg") +# import sys +# sys.path.append("./src/oslg") + +# print(sys.path) import unittest -import oslg +from src.oslg import oslg DBG = oslg.CN.DEBUG INF = oslg.CN.INFO From 28d43d9327a176f9b3f6db892e29292fcbf127d7 Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 25 Jun 2025 10:08:29 -0400 Subject: [PATCH 4/9] Cleanup + complete docstrings --- src/oslg/oslg.py | 280 ++++++++++++++++++++++++++++++++++++++------- tests/test_oslg.py | 38 ++++-- 2 files changed, 263 insertions(+), 55 deletions(-) diff --git a/src/oslg/oslg.py b/src/oslg/oslg.py index cb7b6f7..ef0e5f6 100644 --- a/src/oslg/oslg.py +++ b/src/oslg/oslg.py @@ -27,12 +27,27 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" +Python implementation of the OSlg logger, in support of the OpenStudio SDK. + +Original Ruby implementation/documentation: https://github.com/rd2/oslg +""" + import inspect from dataclasses import dataclass @dataclass(frozen=True) class _CN: + """ + OSlg constants (int): 'DEBUG', 'INFO', 'WARN', 'ERROR' & 'FATAL'. + + Typical usage: + + import oslg + print(oslg.CN.FATAL) + (-> 6) + """ DEBUG = 1 INFO = 2 WARN = 3 @@ -59,48 +74,91 @@ class _CN: _status = 0 -def logs(): - """Returns the logs list.""" +def trim(txt="", length=60) -> str: + """ + Converts an object to a string. Strips if necessary. + + Args: + txt: + An object. + length: + Desired maximum string length. + + Returns: + Stripped, trimmed string. Maximum string length is defaulted at 60 + if 'length' cannot be converted to an integer. Returns an empty string + if 'txt' cannot be converted to a valid string. + + """ + try: + length = int(length) + except ValueError as e: + length = 60 + + try: + txt = str(txt).strip()[:length] + except UnicodeEncodeError: + txt = "" + except Exception as e: + txt = "" + + return txt + + +def logs() -> list: + """Returns generated logs.""" return _logs -def level(): +def level() -> int: """Returns current log level.""" return _level -def status(): +def status() -> int: """Returns current log status.""" return _status -def is_debug(): +def is_debug() -> bool: """Returns whether current status is DEBUG.""" return bool(_status == CN.DEBUG) -def is_info(): +def is_info() -> bool: """Returns whether current status is INFO.""" return bool(_status == CN.INFO) -def is_warn(): +def is_warn() -> bool: """Returns whether current status is WARNING.""" return bool(_status == CN.WARNING) -def is_error(): +def is_error() -> bool: """Returns whether current status is ERROR.""" return bool(_status == CN.ERROR) -def is_fatal(): +def is_fatal() -> bool: """Returns whether current status is FATAL.""" return bool(_status == CN.FATAL) -def tag(lvl=_level): - """Returns preset OSlg string that matches log level.""" +def tag(lvl=_level) -> str: + """ + Returns a preset string that matches a log level. + + Args: + lvl: + Selected log level (e.g. CN.DEBUG). + + Returns: + Matching 'tag' string (e.g. "DEBUG"). Returns an empty string if + 'lvl' cannot be converted to an integer, or if not an OSlg constant + (once converted). + + """ try: lvl = int(lvl) except ValueError as e: @@ -112,8 +170,20 @@ def tag(lvl=_level): return _tag[lvl] -def msg(stat=_status): - """Returns preset OSlg message that matches log status.""" +def msg(stat=_status) -> str: + """ + Returns a preset string that matches a log status. + + Args: + stat: + Selected log status (e.g. CN.FATAL). + + Returns: + Matching 'status' string (e.g. "Failure, triggered fatal errors"). + Returns an empty string if 'stat' cannot be converted to an integer, or + if not an OSlg constant (once converted). + + """ try: stat = int(stat) except ValueError as e: @@ -125,25 +195,19 @@ def msg(stat=_status): return _msg[stat] -def trim(txt="", length=60): - """Converts object to String - trims if necessary.""" - try: - length = int(length) - except ValueError as e: - length = 60 - - try: - txt = str(txt).strip()[:length] - except UnicodeEncodeError: - txt = "" - except Exception as e: - txt = "" +def reset(lvl=CN.DEBUG) -> int: + """ + Resets log level. - return txt + Args: + lvl: + Selected log level (e.g. CN.DEBUG). + Returns: + Newly reset log level. Remains unchanged if 'lvl' cannot be converted + to an integer, or if not an OSlg constant (once converted). -def reset(lvl=CN.DEBUG): - """Resets level, if lvl (input) is within accepted range.""" + """ global _level try: @@ -157,8 +221,25 @@ def reset(lvl=CN.DEBUG): return _level -def log(lvl=CN.DEBUG, message=""): - """Logs a new entry, if provided arguments are valid.""" +def log(lvl=CN.DEBUG, message="") -> int: + """ + Logs a new entry. Overall log status is raised to the new log level, if + the latter is greater than the former (e.g. FATAL > ERROR). Candidate log + entry is ignored and status remains unchanged if the new level cannot be + converted to an integer, or if not an OSlg constant (once converted). + Relies on module method trim(): candidate entry is ignored and status + unchanged if message is not a valid string. + + Args: + lvl: + Selected log level (e.g. CN.DEBUG). + message: + Selected log message (max. 60 chars). + + Returns: + Current log status, potentially raised. + + """ global _status global _logs @@ -181,7 +262,28 @@ def log(lvl=CN.DEBUG, message=""): def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None): - """Logs template 'invalid object' message (~60chars), if valid arguments.""" + """ + Logs template 'invalid object' entry, based on arguments. Relies on module + method log(): check its own exit conditions and module-level side effects. + Argument 'ord' is ignored unless > 0. Candidate log entry is ignored and + status remains unchanged if 'ord' cannot be converted to an integer. + + Args: + id: + Object identifier string (e.g. "circle radius"). + mth: + Method identifier string (e.g. "circle area"). + ord: + Method call parameter index (e.g. '1' if 2nd argument). + lvl: + Selected log level (e.g. CN.DEBUG). + res: + Selected return object. + + Returns: + Selected return object ('res'). + + """ id = trim(id) mth = trim(mth) @@ -210,8 +312,30 @@ def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None): def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None): - """Logs template 'instance/class mismatch' message, if valid arguments.""" - + """ + Logs template 'instance/class mismatch' entry, based on arguments. Relies + on module method log(): check its own exit conditions and module-level + side effects. Candidate log entry is ignored and status remains unchanged + if 'obj' is an instance of 'cl'. + + Args: + id: + Object identifier string (e.g. "circle radius"). + obj: + Mismatched object (e.g. boolean) + cl: + Desired target class (e.g. float) + mth: + Method identifier string (e.g. "circle area"). + lvl: + Selected log level (e.g. CN.DEBUG). + res: + Selected return object. + + Returns: + Selected return object ('res'). + + """ id = trim(id) mth = trim(mth) @@ -233,8 +357,30 @@ def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None): def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None): - """Logs template 'missing hash key' message, if valid arguments.""" - + """ + Logs template 'missing hash key' entry, based on arguments. Relies + on module method log(): check its own exit conditions and module-level + side effects. Candidate log entry is ignored and status remains unchanged + if 'obj' is an instance of 'cl'. + + Args: + id: + Object identifier string (e.g. "circle radius"). + dct: + Dictionary (or Hash) to validate. + key: + Missing dictionary key. + mth: + Method identifier string. + lvl: + Selected log level (e.g. CN.DEBUG). + res: + Selected return object. + + Returns: + Selected return object ('res'). + + """ id = trim(id) mth = trim(mth) ky = trim(key) @@ -255,8 +401,24 @@ def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None): def empty(id="", mth="", lvl=CN.DEBUG, res=None): - """Logs template 'empty' message, if provided arguments are valid.""" - + """ + Logs template 'empty' entry, based on arguments. Relies on module method + log(): check its own exit conditions and module-level side effects. + + Args: + id: + Object identifier string (e.g. "circle radius"). + mth: + Method identifier string. + lvl: + Selected log level (e.g. CN.DEBUG). + res: + Selected return object. + + Returns: + Selected return object ('res'). + + """ id = trim(id) mth = trim(mth) @@ -274,8 +436,24 @@ def empty(id="", mth="", lvl=CN.DEBUG, res=None): def zero(id="", mth="", lvl=CN.DEBUG, res=None): - """Logs template 'zero' value message, if provided arguments are valid.""" - + """ + Logs template 'zero' entry, based on arguments. Relies on module method + log(): check its own exit conditions and module-level side effects. + + Args: + id: + Object identifier string (e.g. "circle radius"). + mth: + Method identifier string. + lvl: + Selected log level (e.g. CN.DEBUG). + res: + Selected return object. + + Returns: + Selected return object ('res'). + + """ id = trim(id) mth = trim(mth) @@ -293,8 +471,24 @@ def zero(id="", mth="", lvl=CN.DEBUG, res=None): def negative(id="", mth="", lvl=CN.DEBUG, res=None): - """Logs template 'negative' message, if provided arguments are valid.""" - + """ + Logs template 'negative' entry, based on arguments. Relies on module method + log(): check its own exit conditions and module-level side effects. + + Args: + id: + Object identifier string (e.g. "circle radius"). + mth: + Method identifier string. + lvl: + Selected log level (e.g. CN.DEBUG). + res: + Selected return object. + + Returns: + Selected return object ('res'). + + """ id = trim(id) mth = trim(mth) @@ -311,7 +505,7 @@ def negative(id="", mth="", lvl=CN.DEBUG, res=None): return res -def clean(): +def clean() -> int: """Resets log status and entries.""" global _status global _logs diff --git a/tests/test_oslg.py b/tests/test_oslg.py index eca9c09..5465ba5 100644 --- a/tests/test_oslg.py +++ b/tests/test_oslg.py @@ -27,11 +27,6 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# import sys -# sys.path.append("./src/oslg") - -# print(sys.path) - import unittest from src.oslg import oslg @@ -73,6 +68,8 @@ def test02_oslg_resets(self): self.assertEqual(oslg.level(), INF) def test03_oslg_invalid_argument_log(self): + m1 = "Invalid 'radius' arg #2 (area)" + m2 = "Invalid 'radius' (area)" self.assertEqual(oslg.level(), INF) self.assertFalse(oslg.logs()) self.assertEqual(oslg.invalid("radius", "area", 2, FTL), None) @@ -81,7 +78,7 @@ def test03_oslg_invalid_argument_log(self): self.assertEqual(oslg.status(), FTL) self.assertEqual(oslg.level(), INF) self.assertEqual(len(oslg.logs()), 1) - self.assertEqual(oslg.logs()[0]["message"], "Invalid 'radius' arg #2 (area)") + self.assertEqual(oslg.logs()[0]["message"], m1) self.assertEqual(oslg.logs()[0]["level"], FTL) self.assertEqual(oslg.reset(INF), INF) self.assertEqual(oslg.clean(), INF) @@ -92,13 +89,15 @@ def test03_oslg_invalid_argument_log(self): self.assertEqual(oslg.status(), FTL) self.assertEqual(oslg.level(), INF) self.assertEqual(len(oslg.logs()), 1) - self.assertEqual(oslg.logs()[0]["message"], "Invalid 'radius' (area)") + self.assertEqual(oslg.logs()[0]["message"], m2) self.assertEqual(oslg.logs()[0]["level"], FTL) self.assertEqual(oslg.reset(INF), INF) self.assertEqual(oslg.clean(), INF) self.assertEqual(oslg.level(), INF) def test04_oslg_mismatched_argument_log(self): + m1 = "'radius' str? expecting float (area)" + m2 = "'roster' list? expecting dict (index)" self.assertEqual(oslg.level(), INF) self.assertFalse(oslg.logs()) self.assertEqual(oslg.mismatch("radius", "5", float, "area", ERR), None) @@ -107,13 +106,25 @@ def test04_oslg_mismatched_argument_log(self): self.assertEqual(oslg.status(), ERR) self.assertEqual(oslg.level(), INF) self.assertEqual(len(oslg.logs()), 1) - self.assertEqual(oslg.logs()[0]["message"], "'radius' str? expecting float (area)") + self.assertEqual(oslg.logs()[0]["message"], m1) + self.assertEqual(oslg.logs()[0]["level"], oslg.status()) + self.assertEqual(oslg.reset(INF), INF) + self.assertEqual(oslg.clean(), INF) + self.assertEqual(oslg.level(), INF) + self.assertEqual(oslg.mismatch("roster", [], dict, "index", ERR), None) + self.assertFalse(oslg.is_info()) + self.assertTrue(oslg.is_error()) + self.assertEqual(oslg.status(), ERR) + self.assertEqual(oslg.level(), INF) + self.assertEqual(len(oslg.logs()), 1) + self.assertEqual(oslg.logs()[0]["message"], m2) self.assertEqual(oslg.logs()[0]["level"], oslg.status()) self.assertEqual(oslg.reset(INF), INF) self.assertEqual(oslg.clean(), INF) self.assertEqual(oslg.level(), INF) def test05_oslg_missing_key_argument_log(self): + m1 = "Missing 'r' key in argh (area)" self.assertEqual(oslg.level(), INF) self.assertFalse(oslg.logs()) self.assertEqual(oslg.hashkey("argh", {"a":3}, "r", "area", ERR), None) @@ -122,13 +133,14 @@ def test05_oslg_missing_key_argument_log(self): self.assertEqual(oslg.status(), ERR) self.assertEqual(oslg.level(), INF) self.assertEqual(len(oslg.logs()), 1) - self.assertEqual(oslg.logs()[0]["message"], "Missing 'r' key in argh (area)") + self.assertEqual(oslg.logs()[0]["message"], m1) self.assertEqual(oslg.logs()[0]["level"], oslg.status()) self.assertEqual(oslg.reset(INF), INF) self.assertEqual(oslg.clean(), INF) self.assertEqual(oslg.level(), INF) def test06_oslg_empty_argument_log(self): + m1 = "Empty 'hash' (area)" self.assertEqual(oslg.level(), INF) self.assertFalse(oslg.logs()) self.assertEqual(oslg.empty("hash", "area", ERR), None) @@ -137,13 +149,14 @@ def test06_oslg_empty_argument_log(self): self.assertEqual(oslg.status(), ERR) self.assertEqual(oslg.level(), INF) self.assertEqual(len(oslg.logs()), 1) - self.assertEqual(oslg.logs()[0]["message"],"Empty 'hash' (area)") + self.assertEqual(oslg.logs()[0]["message"], m1) self.assertEqual(oslg.logs()[0]["level"], oslg.status()) self.assertEqual(oslg.reset(INF), INF) self.assertEqual(oslg.clean(), INF) self.assertEqual(oslg.level(), INF) def test07_oslg_zero_argument_log(self): + m1 = "Zero 'radius' (area)" self.assertEqual(oslg.level(), INF) self.assertFalse(oslg.logs()) self.assertEqual(oslg.zero("radius", "area", ERR), None) @@ -152,13 +165,14 @@ def test07_oslg_zero_argument_log(self): self.assertEqual(oslg.status(), ERR) self.assertEqual(oslg.level(), INF) self.assertEqual(len(oslg.logs()), 1) - self.assertEqual(oslg.logs()[0]["message"],"Zero 'radius' (area)") + self.assertEqual(oslg.logs()[0]["message"], m1) self.assertEqual(oslg.logs()[0]["level"], oslg.status()) self.assertEqual(oslg.reset(INF), INF) self.assertEqual(oslg.clean(), INF) self.assertEqual(oslg.level(), INF) def test07_oslg_zero_argument_log(self): + m1 = "Negative 'radius' (area)" self.assertEqual(oslg.level(), INF) self.assertFalse(oslg.logs()) self.assertEqual(oslg.negative("radius", "area", ERR), None) @@ -167,7 +181,7 @@ def test07_oslg_zero_argument_log(self): self.assertEqual(oslg.status(), ERR) self.assertEqual(oslg.level(), INF) self.assertEqual(len(oslg.logs()), 1) - self.assertEqual(oslg.logs()[0]["message"],"Negative 'radius' (area)") + self.assertEqual(oslg.logs()[0]["message"], m1) self.assertEqual(oslg.logs()[0]["level"], oslg.status()) self.assertEqual(oslg.reset(INF), INF) self.assertEqual(oslg.clean(), INF) From 78c0c1ff35fb9ac87dca47bf387b289fffaab317 Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 25 Jun 2025 17:46:32 -0400 Subject: [PATCH 5/9] Docstrings edits --- src/oslg/oslg.py | 101 ++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/src/oslg/oslg.py b/src/oslg/oslg.py index ef0e5f6..010d379 100644 --- a/src/oslg/oslg.py +++ b/src/oslg/oslg.py @@ -223,18 +223,17 @@ def reset(lvl=CN.DEBUG) -> int: def log(lvl=CN.DEBUG, message="") -> int: """ - Logs a new entry. Overall log status is raised to the new log level, if - the latter is greater than the former (e.g. FATAL > ERROR). Candidate log - entry is ignored and status remains unchanged if the new level cannot be - converted to an integer, or if not an OSlg constant (once converted). - Relies on module method trim(): candidate entry is ignored and status - unchanged if message is not a valid string. + Logs a new entry. Overall log status is raised if new level is greater + (e.g. FATAL > ERROR). Candidate log entry is ignored and status remains + unchanged if the new level cannot be converted to an integer, or if not an + OSlg constant (once converted). Relies on OSlg method 'trim()': candidate + entry is ignored and status unchanged if message is not a valid string. Args: lvl: Selected log level (e.g. CN.DEBUG). message: - Selected log message (max. 60 chars). + Selected log message (max 60 chars). Returns: Current log status, potentially raised. @@ -263,10 +262,11 @@ def log(lvl=CN.DEBUG, message="") -> int: def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None): """ - Logs template 'invalid object' entry, based on arguments. Relies on module - method log(): check its own exit conditions and module-level side effects. - Argument 'ord' is ignored unless > 0. Candidate log entry is ignored and - status remains unchanged if 'ord' cannot be converted to an integer. + Logs template 'invalid object' entry, based on arguments. Relies on OSlg + method 'log()': first check out its own operation, exit conditions and + module side effects. Candidate log entry is ignored and status remains + unchanged if 'ord' cannot be converted to an integer. Argument 'ord' is + ignored unless > 0. Args: id: @@ -278,7 +278,7 @@ def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None): lvl: Selected log level (e.g. CN.DEBUG). res: - Selected return object. + Selected return object (e.g. 'False', None). Returns: Selected return object ('res'). @@ -314,9 +314,9 @@ def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None): def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None): """ Logs template 'instance/class mismatch' entry, based on arguments. Relies - on module method log(): check its own exit conditions and module-level - side effects. Candidate log entry is ignored and status remains unchanged - if 'obj' is an instance of 'cl'. + on OSlg method 'log()': first check out its own operation, exit conditions + and module side effects. Candidate log entry is ignored and status remains + unchanged if 'obj' is an instance of 'cl'. Args: id: @@ -330,7 +330,7 @@ def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None): lvl: Selected log level (e.g. CN.DEBUG). res: - Selected return object. + Selected return object (e.g. 'False', None). Returns: Selected return object ('res'). @@ -344,10 +344,12 @@ def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None): except ValueError as e: return res - if not inspect.isclass(cl) or isinstance(obj, cl): - return res - if not id or not mth or lvl < CN.DEBUG or lvl > CN.FATAL: - return res + if not id: return res + if not mth: return res + if lvl < CN.DEBUG: return res + if lvl > CN.FATAL: return res + if not inspect.isclass(cl): return res + if isinstance(obj, cl): return res msg = "'%s' %s? " % (id, type(obj).__name__) msg += "expecting %s (%s)" % (cl.__name__, mth) @@ -358,10 +360,10 @@ def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None): def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None): """ - Logs template 'missing hash key' entry, based on arguments. Relies - on module method log(): check its own exit conditions and module-level - side effects. Candidate log entry is ignored and status remains unchanged - if 'obj' is an instance of 'cl'. + Logs template 'missing hash key' entry, based on arguments. Relies on OSlg + method 'log()': first check out its own operation, exit conditions and + module side effects. Candidate log entry is ignored and status remains + unchanged if 'key' is found in 'dct'. Args: id: @@ -375,7 +377,7 @@ def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None): lvl: Selected log level (e.g. CN.DEBUG). res: - Selected return object. + Selected return object (e.g. 'False', None). Returns: Selected return object ('res'). @@ -390,10 +392,12 @@ def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None): except ValueError as e: return res - if not isinstance(dct, dict) or key in dct: - return res - if not id or not mth or lvl < CN.DEBUG or lvl > CN.FATAL: - return res + if not id: return res + if not mth: return res + if lvl < CN.DEBUG: return res + if lvl > CN.FATAL: return res + if not isinstance(dct, dict): return res + if key in dct: return res log(lvl, "Missing '%s' key in %s (%s)" % (ky, id, mth)) @@ -402,8 +406,9 @@ def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None): def empty(id="", mth="", lvl=CN.DEBUG, res=None): """ - Logs template 'empty' entry, based on arguments. Relies on module method - log(): check its own exit conditions and module-level side effects. + Logs template 'empty' entry, based on arguments. Relies on OSlg method + 'log()': first check out its own operation, exit conditions and module side + effects. Args: id: @@ -413,7 +418,7 @@ def empty(id="", mth="", lvl=CN.DEBUG, res=None): lvl: Selected log level (e.g. CN.DEBUG). res: - Selected return object. + Selected return object (e.g. 'False', None). Returns: Selected return object ('res'). @@ -427,8 +432,10 @@ def empty(id="", mth="", lvl=CN.DEBUG, res=None): except ValueError as e: return res - if not id or not mth or lvl < CN.DEBUG or lvl > CN.FATAL: - return res + if not id: return res + if not mth: return res + if lvl < CN.DEBUG: return res + if lvl > CN.FATAL: return res log(lvl, "Empty '%s' (%s)" % (id, mth)) @@ -437,8 +444,9 @@ def empty(id="", mth="", lvl=CN.DEBUG, res=None): def zero(id="", mth="", lvl=CN.DEBUG, res=None): """ - Logs template 'zero' entry, based on arguments. Relies on module method - log(): check its own exit conditions and module-level side effects. + Logs template 'zero' entry, based on arguments. Relies on OSlg method + 'log()': first check out its own operation, exit conditions and module side + effects. Args: id: @@ -448,7 +456,7 @@ def zero(id="", mth="", lvl=CN.DEBUG, res=None): lvl: Selected log level (e.g. CN.DEBUG). res: - Selected return object. + Selected return object (e.g. 'False', None). Returns: Selected return object ('res'). @@ -462,8 +470,10 @@ def zero(id="", mth="", lvl=CN.DEBUG, res=None): except ValueError as e: return res - if not id or not mth or lvl < CN.DEBUG or lvl > CN.FATAL: - return res + if not id: return res + if not mth: return res + if lvl < CN.DEBUG: return res + if lvl > CN.FATAL: return res log(lvl, "Zero '%s' (%s)" % (id, mth)) @@ -472,8 +482,9 @@ def zero(id="", mth="", lvl=CN.DEBUG, res=None): def negative(id="", mth="", lvl=CN.DEBUG, res=None): """ - Logs template 'negative' entry, based on arguments. Relies on module method - log(): check its own exit conditions and module-level side effects. + Logs template 'negative' entry, based on arguments. Relies on OSlg method + 'log()': first check out its own operation, exit conditions and module side + effects. Args: id: @@ -483,7 +494,7 @@ def negative(id="", mth="", lvl=CN.DEBUG, res=None): lvl: Selected log level (e.g. CN.DEBUG). res: - Selected return object. + Selected return object (e.g. 'False', None). Returns: Selected return object ('res'). @@ -497,8 +508,10 @@ def negative(id="", mth="", lvl=CN.DEBUG, res=None): except ValueError as e: return res - if not id or not mth or lvl < CN.DEBUG or lvl > CN.FATAL: - return res + if not id: return res + if not mth: return res + if lvl < CN.DEBUG: return res + if lvl > CN.FATAL: return res log(lvl, "Negative '%s' (%s)" % (id, mth)) From e262cddf61d35be0bc2462adb58b8409398447e7 Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 2 Jul 2025 06:57:01 -0400 Subject: [PATCH 6/9] Increasing log message length (160) --- src/oslg/oslg.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/oslg/oslg.py b/src/oslg/oslg.py index 010d379..4ee93be 100644 --- a/src/oslg/oslg.py +++ b/src/oslg/oslg.py @@ -221,7 +221,7 @@ def reset(lvl=CN.DEBUG) -> int: return _level -def log(lvl=CN.DEBUG, message="") -> int: +def log(lvl=CN.DEBUG, message="", length=160) -> int: """ Logs a new entry. Overall log status is raised if new level is greater (e.g. FATAL > ERROR). Candidate log entry is ignored and status remains @@ -230,10 +230,12 @@ def log(lvl=CN.DEBUG, message="") -> int: entry is ignored and status unchanged if message is not a valid string. Args: - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). - message: - Selected log message (max 60 chars). + message (str): + Selected log message. + length (int): + Selected log message length (60 to 160 chars). Returns: Current log status, potentially raised. @@ -247,7 +249,14 @@ def log(lvl=CN.DEBUG, message="") -> int: except ValueError as e: return _status - message = trim(message) + try: + length = int(length) + except ValueError as e: + return _status + + if length < 60 or length > 160: length = 160 + + message = trim(message, length) if not message or lvl < CN.DEBUG or lvl > CN.FATAL or lvl < _level: return _status From 7ebc648badfabb20842721d40412bdd826fe56ed Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 2 Jul 2025 07:05:58 -0400 Subject: [PATCH 7/9] Increasing trim text length (160) --- src/oslg/oslg.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/oslg/oslg.py b/src/oslg/oslg.py index 4ee93be..973baf8 100644 --- a/src/oslg/oslg.py +++ b/src/oslg/oslg.py @@ -74,7 +74,7 @@ class _CN: _status = 0 -def trim(txt="", length=60) -> str: +def trim(txt="", length=160) -> str: """ Converts an object to a string. Strips if necessary. @@ -82,10 +82,10 @@ def trim(txt="", length=60) -> str: txt: An object. length: - Desired maximum string length. + Desired maximum string length (max 160). Returns: - Stripped, trimmed string. Maximum string length is defaulted at 60 + Stripped, trimmed string. Maximum string length is defaulted at 160 if 'length' cannot be converted to an integer. Returns an empty string if 'txt' cannot be converted to a valid string. @@ -93,7 +93,7 @@ def trim(txt="", length=60) -> str: try: length = int(length) except ValueError as e: - length = 60 + length = 160 try: txt = str(txt).strip()[:length] @@ -235,7 +235,7 @@ def log(lvl=CN.DEBUG, message="", length=160) -> int: message (str): Selected log message. length (int): - Selected log message length (60 to 160 chars). + Selected log message length (max 160 chars). Returns: Current log status, potentially raised. @@ -254,7 +254,7 @@ def log(lvl=CN.DEBUG, message="", length=160) -> int: except ValueError as e: return _status - if length < 60 or length > 160: length = 160 + if length > 160: length = 160 message = trim(message, length) From 21642b0e6eb4fa6e65cd8a0983c2411537dfd97e Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 2 Jul 2025 07:13:10 -0400 Subject: [PATCH 8/9] Edits docstrings --- src/oslg/oslg.py | 70 +++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/src/oslg/oslg.py b/src/oslg/oslg.py index 973baf8..333ddbf 100644 --- a/src/oslg/oslg.py +++ b/src/oslg/oslg.py @@ -79,15 +79,15 @@ def trim(txt="", length=160) -> str: Converts an object to a string. Strips if necessary. Args: - txt: + txt (str): An object. - length: + length (int): Desired maximum string length (max 160). Returns: - Stripped, trimmed string. Maximum string length is defaulted at 160 - if 'length' cannot be converted to an integer. Returns an empty string - if 'txt' cannot be converted to a valid string. + str: Stripped, trimmed string. + "": If 'length' cannot be converted to an integer. + "": If 'txt' cannot be converted to a valid string. """ try: @@ -150,13 +150,12 @@ def tag(lvl=_level) -> str: Returns a preset string that matches a log level. Args: - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). Returns: - Matching 'tag' string (e.g. "DEBUG"). Returns an empty string if - 'lvl' cannot be converted to an integer, or if not an OSlg constant - (once converted). + str: Matching 'tag' string (e.g. "DEBUG"). + "": If 'lvl' not an OSlg constant. """ try: @@ -175,13 +174,12 @@ def msg(stat=_status) -> str: Returns a preset string that matches a log status. Args: - stat: + stat (int): Selected log status (e.g. CN.FATAL). Returns: - Matching 'status' string (e.g. "Failure, triggered fatal errors"). - Returns an empty string if 'stat' cannot be converted to an integer, or - if not an OSlg constant (once converted). + str: Matching 'status' string (e.g. "Failure, triggered fatal errors"). + "": If 'stat' not a valid OSlg constant. """ try: @@ -200,12 +198,12 @@ def reset(lvl=CN.DEBUG) -> int: Resets log level. Args: - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). Returns: - Newly reset log level. Remains unchanged if 'lvl' cannot be converted - to an integer, or if not an OSlg constant (once converted). + int: Newly reset log level. Remains unchanged if 'lvl' cannot be + converted to an integer, or if not an OSlg constant (once converted). """ global _level @@ -278,13 +276,13 @@ def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None): ignored unless > 0. Args: - id: + id (str): Object identifier string (e.g. "circle radius"). - mth: + mth (str): Method identifier string (e.g. "circle area"). - ord: + ord (int): Method call parameter index (e.g. '1' if 2nd argument). - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). res: Selected return object (e.g. 'False', None). @@ -328,15 +326,15 @@ def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None): unchanged if 'obj' is an instance of 'cl'. Args: - id: + id (str): Object identifier string (e.g. "circle radius"). obj: Mismatched object (e.g. boolean) cl: Desired target class (e.g. float) - mth: + mth (str): Method identifier string (e.g. "circle area"). - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). res: Selected return object (e.g. 'False', None). @@ -375,15 +373,15 @@ def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None): unchanged if 'key' is found in 'dct'. Args: - id: + id (str): Object identifier string (e.g. "circle radius"). - dct: + dct (dict): Dictionary (or Hash) to validate. key: Missing dictionary key. - mth: + mth (str): Method identifier string. - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). res: Selected return object (e.g. 'False', None). @@ -420,11 +418,11 @@ def empty(id="", mth="", lvl=CN.DEBUG, res=None): effects. Args: - id: + id (str): Object identifier string (e.g. "circle radius"). - mth: + mth (str): Method identifier string. - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). res: Selected return object (e.g. 'False', None). @@ -458,11 +456,11 @@ def zero(id="", mth="", lvl=CN.DEBUG, res=None): effects. Args: - id: + id (str): Object identifier string (e.g. "circle radius"). - mth: + mth (str): Method identifier string. - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). res: Selected return object (e.g. 'False', None). @@ -496,11 +494,11 @@ def negative(id="", mth="", lvl=CN.DEBUG, res=None): effects. Args: - id: + id (str): Object identifier string (e.g. "circle radius"). - mth: + mth (str): Method identifier string. - lvl: + lvl (int): Selected log level (e.g. CN.DEBUG). res: Selected return object (e.g. 'False', None). From 22b91df6ffcaff3d1871017f3600de2516b8ac8a Mon Sep 17 00:00:00 2001 From: brgix Date: Wed, 2 Jul 2025 07:14:20 -0400 Subject: [PATCH 9/9] Version change --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c19eac2..38cae47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "oslg" -version = "0.3.0a2" +version = "0.3.0" description = "OpenStudio SDK logger for Python" readme = "README.md" requires-python = ">=3.2"