Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "oslg"
version = "0.3.3"
version = "0.4.0"
description = "OpenStudio SDK logger for Python"
readme = "README.md"
requires-python = ">=3.2"
Expand Down
67 changes: 36 additions & 31 deletions src/oslg/oslg.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,31 +74,31 @@ class _CN:
_status = 0


def trim(txt="", length=160) -> str:
def trim(txt="", sz=None) -> str:
"""
Converts an object to a string. Strips if necessary.

Args:
txt (str):
An object.
length (int):
Desired maximum string length (max 160).
sz (int):
Selected maximum string length, or 'size' (optional).

Returns:
str: Stripped, trimmed string.
"": If 'length' cannot be converted to an integer.
"": If 'txt' cannot be converted to a valid string.

"""
try:
length = int(length)
txt = str(txt).strip()
except:
length = 160
txt = ""

try:
txt = str(txt).strip()[:length]
sz = int(sz)
if len(txt) > sz: txt = txt[:sz] + " ..."
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revisiting a recent change on managing log message lengths, having tested it with other packages (i.e. OSlg as a dependency).

OSlg shall no longer have a built-in limit to log message lengths. Good option to offer, but not one to bake in. All OSlg log functions (e.g. zero, mismatch) call on log, which itself calls trim:

  • ensures valid log message strings
  • trims final log message length if requested by user
  • if trimming not requested by user, leaves log message as is

Each OSlg log function now has an additional sz parameter, which is None by default (and therefore ignored). Users are free to set sz to e.g. "160" chars.

except:
txt = ""
pass

return txt

Expand Down Expand Up @@ -217,7 +217,7 @@ def reset(lvl=CN.DEBUG) -> int:
return _level


def log(lvl=CN.DEBUG, message="", length=160) -> int:
def log(lvl=CN.DEBUG, message="", sz=None) -> 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
Expand All @@ -230,8 +230,8 @@ def log(lvl=CN.DEBUG, message="", length=160) -> int:
Selected log level (e.g. CN.DEBUG).
message (str):
Selected log message.
length (int):
Selected log message length (max 160 chars).
sz (int):
Selected maximum string length, or 'size' (optional).

Returns:
Current log status, potentially raised.
Expand All @@ -245,14 +245,7 @@ def log(lvl=CN.DEBUG, message="", length=160) -> int:
except:
return _status

try:
length = int(length)
except:
return _status

if length > 160: length = 160

message = trim(message, length)
message = trim(message, sz)

if not message or lvl < CN.DEBUG or lvl > CN.FATAL or lvl < _level:
return _status
Expand All @@ -265,7 +258,7 @@ def log(lvl=CN.DEBUG, message="", length=160) -> int:
return _status


def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None):
def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None, sz=None):
"""
Logs template 'invalid object' entry, based on arguments. Relies on OSlg
method 'log()': first check out its own operation, exit conditions and
Expand All @@ -284,6 +277,8 @@ def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None):
Selected log level (e.g. CN.DEBUG).
res:
Selected return object (e.g. 'False', None).
sz (int):
Selected maximum string length, or 'size' (optional).

Returns:
Selected return object ('res').
Expand Down Expand Up @@ -311,12 +306,12 @@ def invalid(id="", mth="", ord=0, lvl=CN.DEBUG, res=None):
msg += "arg #%d " % (ord)

msg += "(%s)" % (mth)
log(lvl, msg)
log(lvl, msg, sz)

return res


def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None):
def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None, sz=None):
"""
Logs template 'instance/class mismatch' entry, based on arguments. Relies
on OSlg method 'log()': first check out its own operation, exit conditions
Expand All @@ -336,6 +331,8 @@ def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None):
Selected log level (e.g. CN.DEBUG).
res:
Selected return object (e.g. 'False', None).
sz (int):
Selected maximum string length, or 'size' (optional).

Returns:
Selected return object ('res').
Expand All @@ -358,12 +355,12 @@ def mismatch(id="", obj=None, cl=None, mth="", lvl=CN.DEBUG, res=None):

msg = "'%s' %s? " % (id, type(obj).__name__)
msg += "expecting %s (%s)" % (cl.__name__, mth)
log(lvl, msg)
log(lvl, msg, sz)

return res


def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None):
def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None, sz=None):
"""
Logs template 'missing hash key' entry, based on arguments. Relies on OSlg
method 'log()': first check out its own operation, exit conditions and
Expand All @@ -383,6 +380,8 @@ def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None):
Selected log level (e.g. CN.DEBUG).
res:
Selected return object (e.g. 'False', None).
sz (int):
Selected maximum string length, or 'size' (optional).

Returns:
Selected return object ('res').
Expand All @@ -404,12 +403,12 @@ def hashkey(id="", dct={}, key="", mth="", lvl=CN.DEBUG, res=None):
if not isinstance(dct, dict): return res
if key in dct: return res

log(lvl, "Missing '%s' key in %s (%s)" % (ky, id, mth))
log(lvl, "Missing '%s' key in %s (%s)" % (ky, id, mth), sz)

return res


def empty(id="", mth="", lvl=CN.DEBUG, res=None):
def empty(id="", mth="", lvl=CN.DEBUG, res=None, sz=None):
"""
Logs template 'empty' entry, based on arguments. Relies on OSlg method
'log()': first check out its own operation, exit conditions and module side
Expand All @@ -424,6 +423,8 @@ def empty(id="", mth="", lvl=CN.DEBUG, res=None):
Selected log level (e.g. CN.DEBUG).
res:
Selected return object (e.g. 'False', None).
sz (int):
Selected maximum string length, or 'size' (optional).

Returns:
Selected return object ('res').
Expand All @@ -442,12 +443,12 @@ def empty(id="", mth="", lvl=CN.DEBUG, res=None):
if lvl < CN.DEBUG: return res
if lvl > CN.FATAL: return res

log(lvl, "Empty '%s' (%s)" % (id, mth))
log(lvl, "Empty '%s' (%s)" % (id, mth), sz)

return res


def zero(id="", mth="", lvl=CN.DEBUG, res=None):
def zero(id="", mth="", lvl=CN.DEBUG, res=None, sz=None):
"""
Logs template 'zero' entry, based on arguments. Relies on OSlg method
'log()': first check out its own operation, exit conditions and module side
Expand All @@ -462,6 +463,8 @@ def zero(id="", mth="", lvl=CN.DEBUG, res=None):
Selected log level (e.g. CN.DEBUG).
res:
Selected return object (e.g. 'False', None).
sz (int):
Selected maximum string length, or 'size' (optional).

Returns:
Selected return object ('res').
Expand All @@ -480,12 +483,12 @@ def zero(id="", mth="", lvl=CN.DEBUG, res=None):
if lvl < CN.DEBUG: return res
if lvl > CN.FATAL: return res

log(lvl, "Zero '%s' (%s)" % (id, mth))
log(lvl, "Zero '%s' (%s)" % (id, mth), sz)

return res


def negative(id="", mth="", lvl=CN.DEBUG, res=None):
def negative(id="", mth="", lvl=CN.DEBUG, res=None, sz=None):
"""
Logs template 'negative' entry, based on arguments. Relies on OSlg method
'log()': first check out its own operation, exit conditions and module side
Expand All @@ -500,6 +503,8 @@ def negative(id="", mth="", lvl=CN.DEBUG, res=None):
Selected log level (e.g. CN.DEBUG).
res:
Selected return object (e.g. 'False', None).
sz (int):
Selected maximum string length, or 'size' (optional).

Returns:
Selected return object ('res').
Expand All @@ -518,7 +523,7 @@ def negative(id="", mth="", lvl=CN.DEBUG, res=None):
if lvl < CN.DEBUG: return res
if lvl > CN.FATAL: return res

log(lvl, "Negative '%s' (%s)" % (id, mth))
log(lvl, "Negative '%s' (%s)" % (id, mth), sz)

return res

Expand Down
26 changes: 25 additions & 1 deletion tests/test_oslg.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def test01_oslg_initialized(self):
self.assertEqual(oslg.msg(FTL), "Failure, triggered fatal errors")
self.assertNotEqual(oslg.msg(FTL), "Debugging ...")
self.assertEqual(oslg.trim(" oslg "), "oslg")
self.assertEqual(oslg.trim(" oslg ", 3), "osl")
self.assertEqual(oslg.trim(" oslg ", 3), "osl ...")
self.assertEqual(oslg.trim(" oslg ", 64), "oslg")
self.assertEqual(oslg.reset(INF), INF)
self.assertEqual(oslg.clean(), INF)
Expand Down Expand Up @@ -99,6 +99,30 @@ def test03_oslg_invalid_argument_log(self):
self.assertEqual(oslg.clean(), INF)
self.assertEqual(oslg.level(), INF)

# Longish error message, exceeding 160 chars.
a = str([i+1 for i in range(60)])
l1 = 3 * 9 # "1, " + "2, " + "3, " ...+ "9, "
l2 = 4 * (59 - 9) # "10, " + "11, " + 12, ...+ "59, "
l3 = 2 # "60"
l4 = 2 # "[]"
self.assertEqual(l1 + l2 + l3 + l4, 231)
self.assertEqual(len(a), l1 + l2 + l3 + l4)
self.assertEqual(oslg.mismatch("x", "String", list, a, FTL, None, 156), None)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To request a shortened logged message, users need to activate the last log function parameter, sz (here, "156").

Tested, works, hopefully done. Certainly not keen on re-releasing in the future (unless absolutely necessary, e.g. bug, future Python change). So definitely trying to nail this down ASAP.

Running larger test suites (e.g. parent packages, calling upon OSlg). Will only merge and re-release OSlg once all other test suites pass.

self.assertEqual(oslg.status(), FTL)
str1 = "'x' str? expecting list " # 24 chars
str2 = "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, " # 45 chars
str3 = "14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, " # 44 chars
str4 = "25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, ..." # 47 chars
str0 = str1 + str2 + str3 + str4
self.assertEqual(len(str0), 160) # 156 + " ..."
self.assertEqual(len(oslg.logs()[0]["message"]), len(str0))
self.assertEqual(oslg.logs()[0]["message"], str0)
self.assertEqual(oslg.level(), INF)
self.assertEqual(len(oslg.logs()), 1)
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)"
Expand Down